{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://course.rs/basic/intro.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "( a + b ) + ( c + d ) = 90\n"
     ]
    }
   ],
   "source": [
    "// 开始之前先通过一段代码来简单浏览下 Rust 的语法：\n",
    "\n",
    "// Rust 程序入口函数，跟其它语言一样，都是 main，该函数目前无返回值\n",
    "fn main() {\n",
    "    // 使用let来声明变量，进行绑定，a是不可变的\n",
    "    // 此处没有指定a的类型，编译器会默认根据a的值为a推断类型：i32，有符号32位整数\n",
    "    // 语句的末尾必须以分号结尾\n",
    "    let a = 10;\n",
    "    // 主动指定b的类型为i32\n",
    "    let b: i32 = 20;\n",
    "    // 这里有两点值得注意：\n",
    "    // 1. 可以在数值中带上类型:30i32表示数值是30，类型是i32\n",
    "    // 2. c是可变的，mut是mutable的缩写\n",
    "    let mut c = 30i32;\n",
    "    // 还能在数值和类型中间添加一个下划线，让可读性更好\n",
    "    let d = 30_i32;\n",
    "    // 跟其它语言一样，可以使用一个函数的返回值来作为另一个函数的参数\n",
    "    let e = add(add(a, b), add(c, d));\n",
    "\n",
    "    // println!是宏调用，看起来像是函数但是它返回的是宏定义的代码块\n",
    "    // 该函数将指定的格式化字符串输出到标准输出中(控制台)\n",
    "    // {}是占位符，在具体执行过程中，会把e的值代入进来\n",
    "    println!(\"( a + b ) + ( c + d ) = {}\", e);\n",
    "}\n",
    "\n",
    "// 定义一个函数，输入两个i32类型的32位有符号整数，返回它们的和\n",
    "fn add(i: i32, j: i32) -> i32 {\n",
    "    // 返回相加值，这里可以省略return\n",
    "    i + j\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 字符串使用双引号 `\"\"` 而不是单引号 `''`，Rust 中单引号是留给单个字符类型（`char`）使用的\n",
    "- Rust 使用 `{}` 来作为格式化输出占位符，其它语言可能使用的是 `%s`，`%d`，`%p` 等，由于 `println!` 会自动推导出具体的类型，因此无需手动指定"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "mismatched types",
     "output_type": "error",
     "traceback": [
      "fn add(i: i32, j: i32) -> i32 {",
      "\u001b[91m                          ^^^\u001b[0m \u001b[94mexpected `i32`, found `()`\u001b[0m",
      "fn add(i: i32, j: i32) -> i32 {",
      "\u001b[91m   ^^^\u001b[0m \u001b[94mimplicitly returns `()` as its body has no tail or `return` expression\u001b[0m",
      "mismatched types",
      "\u001b[1mhelp\u001b[0m: remove this semicolon to return this value\n\n"
     ]
    }
   ],
   "source": [
    "fn add(i: i32, j: i32) -> i32 {\n",
    "    // 返回相加值，这里可以省略return\n",
    "    i + j; // 是表达式(), 不是i32\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.1 变量绑定与解构 / variable\n",
    "\n",
    "- https://course.rs/basic/variable.html\n",
    "- https://practice-zh.course.rs/variables.html\n",
    "\n",
    "**为何要手动设置变量的可变性？**\n",
    "- Rust 同时拥抱可变与不可变变量，在灵活性与安全性之间取得平衡，既让开发者受益也让底层实现更复杂，却换来了运行时更高效的性能。\n",
    "\n",
    "**变量命名**\n",
    "- [命名规范](https://course.rs/practice/naming.html)\n",
    "\n",
    "**变量绑定**\n",
    "- 在 Rust 中称其为“变量绑定”更贴切，因为它体现了**所有权**的核心原则——将内存对象与变量绑定意味着变量成为它的主人，原先的所有者随之失去所有权，这也为后续理解 Rust 的内存管理奠定基础\n",
    "\n",
    "**变量可变性**\n",
    "- Rust 默认不可变的变量设计提升了安全性与可预测性；若要修改则需显式使用 `mut`，既传达意图又在必要场景下带来灵活与性能优势，而选择可变或不可变需根据数据规模、性能要求与代码可读性综合权衡。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot assign twice to immutable variable `x`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0384] Error:\u001b[0m cannot assign twice to immutable variable `x`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_3:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m5\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m first assignment to `x`",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;68m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider making this binding mutable: `mut `",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mx\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100m=\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100m6\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m       \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m cannot assign twice to immutable variable",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;115mNote\u001b[0m: You can change an existing variable to mutable like: `let mut x = x;`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let x = 5;\n",
    "    println!(\"The value of x is: {}\", x);\n",
    "    x = 6;\n",
    "    println!(\"The value of x is: {}\", x);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The value of x is: 5\n",
      "The value of x is: 6\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let mut x = 5;\n",
    "    println!(\"The value of x is: {}\", x);\n",
    "    x = 6;\n",
    "    println!(\"The value of x is: {}\", x);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**使用下划线开头忽略未使用的变量**\n",
    "- 更多关于 `_x` 的使用信息，请阅读后面的[模式匹配章节](https://course.rs/basic/match-pattern/all-patterns.html?highlight=_#使用下划线开头忽略未使用的变量)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let _x = 5;\n",
    "    let y = 10;\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "Shell command failed with exit code 127: warning: unused variable: `y`\n --> unused_variable.rs:3:9\n  |\n3 |     let y = 10;\n  |         ^ help: if this is intentional, prefix it with an underscore: `_y`\n  |\n  = note: `#[warn(unused_variables)]` on by default\n\nwarning: 1 warning emitted\n\nsh: 1: ./main: not found\n",
     "output_type": "error",
     "traceback": [
      "Shell command failed with exit code 127: warning: unused variable: `y`\n --> unused_variable.rs:3:9\n  |\n3 |     let y = 10;\n  |         ^ help: if this is intentional, prefix it with an underscore: `_y`\n  |\n  = note: `#[warn(unused_variables)]` on by default\n\nwarning: 1 warning emitted\n\nsh: 1: ./main: not found\n"
     ]
    }
   ],
   "source": [
    "! cd variable/unused_variable/src && rustc unused_variable.rs && ./main"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "   Compiling unused_variable v0.1.0 (/mnt/d/dev_learn/learnrustbyai_fk/rust_course/01_intro/variable/unused_variable)\n",
       "warning: unused variable: `y`\n",
       " --> src/main.rs:3:9\n",
       "  |\n",
       "3 |     let y = 10;\n",
       "  |         ^ help: if this is intentional, prefix it with an underscore: `_y`\n",
       "  |\n",
       "  = note: `#[warn(unused_variables)]` on by default\n",
       "\n",
       "warning: `unused_variable` (bin \"unused_variable\") generated 1 warning\n",
       "    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.15s\n",
       "     Running `target/debug/unused_variable`\n"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd variable/unused_variable && cargo run"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**变量解构**\n",
    "- let 表达式不仅仅用于变量的绑定，还能进行复杂变量的解构：从一个相对复杂的变量中，匹配出该变量的一部分内容："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a = true, b = false\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let (a, mut b): (bool,bool) = (true, false);\n",
    "    // a = true,不可变; b = false，可变\n",
    "    println!(\"a = {:?}, b = {:?}\", a, b);\n",
    "\n",
    "    b = true;\n",
    "    assert_eq!(a, b);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**变量解构-解构式赋值**\n",
    "- 在 Rust 1.59 版本后，我们可以在赋值语句的左式中使用元组、切片和结构体模式了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Struct {\n",
    "    e: i32\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let (a, b, c, d, e); // 声明了5个未初始化的变量。在 Rust 中，可以先声明变量，稍后再赋值。\n",
    "\n",
    "    (a, b) = (1, 2); // 将元组 (1, 2) 解构赋值给 a 和 b，所以 a = 1, b = 2。\n",
    "    // _ 代表匹配一个值，但是我们不关心具体的值是什么，因此没有使用一个变量名而是使用了 _\n",
    "    [c, .., d, _] = [1, 2, 3, 4, 5]; // 数组切片模式匹配\n",
    "    Struct { e, .. } = Struct { e: 5 }; // 结构体解构: 这不是在创建结构体,而是一个模式,用于从右边的结构体中提取值\n",
    "\n",
    "    assert_eq!([1, 2, 1, 4, 5], [a, b, c, d, e]); // 验证各变量的值\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这段代码展示了 Rust 强大的模式匹配能力，可以优雅地从复杂数据结构中提取所需的值。\n",
    "\n",
    "需要注意的是，使用 `+=` 的赋值语句还不支持解构式赋值\n",
    "\n",
    "`[c, .., d, _] = [1, 2, 3, 4, 5];`:\n",
    "- `c` 匹配第一个元素：`c = 1`\n",
    "- `..` 是**剩余模式**，匹配中间的任意数量元素（这里是 `2, 3`），但不绑定到变量\n",
    "- `d` 匹配倒数第二个元素：`d = 4`\n",
    "- `_` 是**通配符**，匹配最后一个元素 `5`，但忽略它\n",
    "\n",
    "`Struct { e, .. } = Struct { e: 5 };`: 从结构体中提取字段\n",
    "- `e` 使用了**字段简写**语法，等价于 `e: e`，提取字段 `e` 的值到同名变量\n",
    "- `..` 忽略结构体的其他字段（虽然这里只有一个字段）\n",
    "- 所以 `e = 5`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**变量和常量之间的差异**\n",
    "- Rust 中的常量使用 `const` 声明，需显式标注类型，且自始至终不可变，不能与 `mut` 搭配。\n",
    "- 常量可在任意作用域（含全局）定义，且在其作用域内永久有效，适合表示多处共享的、固定的硬编码值。\n",
    "- 命名约定：全大写字母，以下划线分隔单词，数字字面量可加下划线增强可读性，如 `const MAX_POINTS: u32 = 100_000;`。\n",
    "- 将硬编码值集中定义为常量，有利于维护和修改——只需更新一处即可。\n",
    "\n",
    "**变量遮蔽(shadowing)**\n",
    "- 变量遮蔽允许在同一作用域或内层作用域内用 `let` 重新绑定同名变量，从而在不改变原变量类型的前提下以新值（甚至新类型）替换旧值，并避免需要新名字。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The value of x in the inner scope is: 12\n",
      "The value of x is: 6\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let x = 5;\n",
    "    // 在main函数的作用域内对之前的x进行遮蔽\n",
    "    let x = x + 1;\n",
    "\n",
    "    {\n",
    "        // 在当前的花括号作用域内，对之前的x进行遮蔽\n",
    "        let x = x * 2;\n",
    "        println!(\"The value of x in the inner scope is: {}\", x);\n",
    "    }\n",
    "\n",
    "    println!(\"The value of x is: {}\", x);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 字符串类型\n",
    "let spaces = \"   \";\n",
    "// usize数值类型\n",
    "let spaces = spaces.len();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "mismatched types",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0308] Error:\u001b[0m mismatched types",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_12:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m\"\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100m\"\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                  \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m expected due to this value",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249ms\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54m.\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected `&str`, found `usize`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let mut spaces = \"   \";\n",
    "spaces = spaces.len();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> AI:\n",
    "\n",
    "Rust 中的“变量遮蔽”（shadowing）只是编译期的名字解析行为：在内层作用域里用同名标识符重新绑定一个值，临时“盖住”外层的同名变量。它没有运行时的性能开销，也不会改变外层变量的真实值，但可能带来以下副作用或风险：\n",
    "\n",
    "1. **可读性下降 / 语义混淆**\n",
    "   - 在 `match` 分支里看到 `y` 时，如果不了解遮蔽规则，就容易误以为使用的是外层 `y = 10`。\n",
    "   - 代码维护时可能误判当前变量指向的实际值，导致逻辑错误。\n",
    "2. **无法直接访问外层同名变量**\n",
    "   - 被遮蔽后，在该分支内部已经无法再引用外层的 `y`。想比较外层 `y` 的时候，只能换一个名字或使用匹配守卫（`Some(n) if n == y`）。\n",
    "3. **与可变绑定/借用相关的潜在困惑**\n",
    "   - 即使外层变量是 `mut y`，在分支中遮蔽后得到的是一个新的不可变绑定（除非显式写成 `Some(mut y)`），这样会让“我以为在修改外层变量”变成了“实际上只是在改新变量”。\n",
    "   - 遮蔽也可能让人误判借用生命周期：新的绑定与旧的没有关系，旧的借用状态不受影响，但阅读代码时不容易察觉。\n",
    "\n",
    "总体来说，遮蔽本身是安全且常用的语法特性；副作用主要来自可读性和理解上的“陷阱”。如果想避免混淆，可以：\n",
    "\n",
    "- 改用不同的变量名（例如 `Some(value)`）。\n",
    "- 需要比较外层值时，用匹配守卫：`Some(n) if n == y => ...`。\n",
    "- 或者提早把 `x` 解构到新变量里，再处理逻辑。\n",
    "\n",
    "这样既能保持语义清晰，又不影响编译器的判定。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "显然，Rust 对类型的要求很严格，不允许将整数类型 usize 赋值给字符串类型。usize 是一种 CPU 相关的整数类型，在[数值类型](https://course.rs/basic/base-type/numbers.html#%E6%95%B4%E6%95%B0%E7%B1%BB%E5%9E%8B)中有详细介绍。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.2. 基本类型 / Basic Types\n",
    "\n",
    "- 数值类型：有符号整数 (`i8`, `i16`, `i32`, `i64`, `isize`)、 无符号整数 (`u8`, `u16`, `u32`, `u64`, `usize`) 、浮点数 (`f32`, `f64`)、以及有理数、复数\n",
    "- 字符串：字符串字面量和字符串切片 `&str`\n",
    "- 布尔类型：`true` 和 `false`\n",
    "- 字符类型：表示单个 Unicode 字符，存储为 4 个字节\n",
    "- 单元类型：即 `()` ，其唯一的值也是 `()`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**类型推导与标注**\n",
    "- Rust 编译器可以根据变量的值和上下文中的使用方式来自动推导出变量的类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "type annotations needed",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0284] Error:\u001b[0m type annotations needed",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_13:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mg\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m4\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mN\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;68m│\u001b[0m       \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m       \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m error: type annotations needed",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;68m│\u001b[0m         \u001b[38;5;54m│\u001b[0m    ",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider giving `guess` an explicit type: `: /* Type */`",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;54m│\u001b[0m    ",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m type must be known at this point",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let guess = \"42\".parse().expect(\"Not a number!\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "let guess = \"42\".parse::<i32>().expect(\"Not a number!\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "let guess : i32  = \"42\".parse().expect(\"Not a number!\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数值类型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 整数类型\n",
    "\n",
    "Rust 中的内置的整数类型：\n",
    "\n",
    "| 长度       | 有符号类型 | 无符号类型 |\n",
    "| ---------- | ---------- | ---------- |\n",
    "| 8 位       | `i8`       | `u8`       |\n",
    "| 16 位      | `i16`      | `u16`      |\n",
    "| 32 位      | `i32`      | `u32`      |\n",
    "| 64 位      | `i64`      | `u64`      |\n",
    "| 128 位     | `i128`     | `u128`     |\n",
    "| 视架构而定 | `isize`    | `usize`    |\n",
    "\n",
    "- 类型定义的形式统一为：有无符号 + 类型大小(位数)\n",
    "- 有符号数字以补码形式存储\n",
    "- 每个有符号类型规定的数字范围是 -$2^{n - 1}$ ~ $2^{n - 1} - 1$，其中 n 是该定义形式的位长度\n",
    "- 无符号类型可以存储的数字范围是 0 ~ $2^{n - 1}$\n",
    "- 此外，`isize` 和 `usize` 类型取决于程序运行的计算机 CPU 类型： 若 CPU 是 32 位的，则这两个类型是 32 位的，同理，若 CPU 是 64 位，那么它们则是 64 位。\n",
    "\n",
    "整型字面量可以用下表的形式书写：\n",
    "\n",
    "| 数字字面量         | 示例          |\n",
    "| ------------------ | ------------- |\n",
    "| 十进制             | `98_222`      |\n",
    "| 十六进制           | `0xff`        |\n",
    "| 八进制             | `0o77`        |\n",
    "| 二进制             | `0b1111_0000` |\n",
    "| 字节 (仅限于 `u8`) | `b'A'`        |\n",
    "\n",
    "- ust 整型默认使用 i32\n",
    "\n",
    "**整型溢出**\n",
    "- Rust 在 debug 模式下遇到整型溢出会 panic，而在 release 模式下则按补码循环处理\n",
    "\n",
    "要显式处理可能的溢出，可以使用标准库针对原始数字类型提供的这些方法：\n",
    "- 使用 `wrapping_*` 方法在所有模式下都按照补码循环溢出规则处理，例如 `wrapping_add`\n",
    "- 如果使用 `checked_*` 方法时发生溢出，则返回 `None` 值\n",
    "- 使用 `overflowing_*` 方法返回该值和一个指示是否存在溢出的布尔值\n",
    "- 使用 `saturating_*` 方法，可以限定计算后的结果不超过目标类型的最大值或低于最小值，例如:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert_eq!(100u8.saturating_add(1), 101);\n",
    "assert_eq!(u8::MAX.saturating_add(127), u8::MAX);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let a : u8 = 255;\n",
    "    let b = a.wrapping_add(20);\n",
    "    println!(\"{}\", b);  // 19\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 浮点类型\n",
    "\n",
    "在 Rust 中浮点类型数字也有两种基本类型： `f32` 和 `f64`，分别为 32 位和 64 位大小。默认浮点类型是 `f64`，在现代的 CPU 中它的速度与 `f32` 几乎相同，但精度更高。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let x = 2.0; // f64\n",
    "\n",
    "    let y: f32 = 3.0; // f32\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**浮点数陷阱**\n",
    "- 浮点数因二进制表示的近似误差和缺乏完全等价比较而易出错，使用中应避免直接相等测试并对潜在未定义结果格外谨慎。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:4:3:\n",
      "assertion failed: 0.1 + 0.2 == 0.3\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: core::panicking::panic\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:145:5\n",
      "   3: ctx::main\n",
      "   4: run_user_code_1\n",
      "   5: evcxr::runtime::Runtime::run_loop\n",
      "   6: evcxr::runtime::runtime_hook\n",
      "   7: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "  // 断言0.1 + 0.2与0.3相等\n",
    "  assert!(0.1 + 0.2 == 0.3);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "Shell command failed with exit code 101:     Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.05s\n     Running `target/debug/float_eq RUST_BACKTRACE=1`\n\nthread 'main' panicked at src/main.rs:3:3:\nassertion failed: 0.1 + 0.2 == 0.3\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n",
     "output_type": "error",
     "traceback": [
      "Shell command failed with exit code 101:     Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.05s\n     Running `target/debug/float_eq RUST_BACKTRACE=1`\n\nthread 'main' panicked at src/main.rs:3:3:\nassertion failed: 0.1 + 0.2 == 0.3\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n"
     ]
    }
   ],
   "source": [
    "! cd variable/float_eq && cargo run"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "Shell command failed with exit code 101:     Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.05s\n     Running `target/debug/float_eq RUST_BACKTRACE=1`\n\nthread 'main' panicked at src/main.rs:3:3:\nassertion failed: 0.1 + 0.2 == 0.3\nstack backtrace:\n   0: __rustc::rust_begin_unwind\n             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n   1: core::panicking::panic_fmt\n             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n   2: core::panicking::panic\n             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:145:5\n   3: float_eq::main\n             at ./src/main.rs:3:3\n   4: core::ops::function::FnOnce::call_once\n             at /home/ningliu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:253:5\nnote: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n",
     "output_type": "error",
     "traceback": [
      "Shell command failed with exit code 101:     Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.05s\n     Running `target/debug/float_eq RUST_BACKTRACE=1`\n\nthread 'main' panicked at src/main.rs:3:3:\nassertion failed: 0.1 + 0.2 == 0.3\nstack backtrace:\n   0: __rustc::rust_begin_unwind\n             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n   1: core::panicking::panic_fmt\n             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n   2: core::panicking::panic\n             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:145:5\n   3: float_eq::main\n             at ./src/main.rs:3:3\n   4: core::ops::function::FnOnce::call_once\n             at /home/ningliu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:253:5\nnote: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "! cd variable/float_eq && export RUST_BACKTRACE=1 && cargo run"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! cd variable/float_eq && export RUST_BACKTRACE=full && cargo run"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let lhs = 0.1_f64 + 0.2;\n",
    "    let rhs = 0.3_f64;\n",
    "\n",
    "    assert!((lhs - rhs).abs() < 1e-10, \"difference = {}\", (lhs - rhs).abs());\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "abc (f32)\n",
      "   0.1 + 0.2: 3e99999a\n",
      "         0.3: 3e99999a\n",
      "\n",
      "xyz (f64)\n",
      "   0.1 + 0.2: 3fd3333333333334\n",
      "         0.3: 3fd3333333333333\n",
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:17:5:\n",
      "assertion failed: xyz.0 + xyz.1 == xyz.2\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: core::panicking::panic\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:145:5\n",
      "   3: <unknown>\n",
      "   4: <unknown>\n",
      "   5: evcxr::runtime::Runtime::run_loop\n",
      "   6: evcxr::runtime::runtime_hook\n",
      "   7: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let abc: (f32, f32, f32) = (0.1, 0.2, 0.3);\n",
    "    let xyz: (f64, f64, f64) = (0.1, 0.2, 0.3);\n",
    "\n",
    "    println!(\"abc (f32)\");\n",
    "    println!(\"   0.1 + 0.2: {:x}\", (abc.0 + abc.1).to_bits());\n",
    "    println!(\"         0.3: {:x}\", (abc.2).to_bits());\n",
    "    println!();\n",
    "\n",
    "    println!(\"xyz (f64)\");\n",
    "    println!(\"   0.1 + 0.2: {:x}\", (xyz.0 + xyz.1).to_bits());\n",
    "    println!(\"         0.3: {:x}\", (xyz.2).to_bits());\n",
    "    println!();\n",
    "\n",
    "    assert!(abc.0 + abc.1 == abc.2);\n",
    "    assert!(xyz.0 + xyz.1 == xyz.2);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**NaN**\n",
    "- 对于数学上未定义的结果，例如对负数取平方根 `-42.1.sqrt()` ，会产生一个特殊的结果：Rust 的浮点数类型使用 `NaN` (not a number) 来处理这些情况。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:4:3:\n",
      "assertion `left == right` failed\n",
      "  left: NaN\n",
      " right: NaN\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: core::panicking::assert_failed_inner\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:448:17\n",
      "   3: core::panicking::assert_failed\n",
      "   4: ctx::main\n",
      "   5: run_user_code_1\n",
      "   6: evcxr::runtime::Runtime::run_loop\n",
      "   7: evcxr::runtime::runtime_hook\n",
      "   8: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "// 所有跟 NaN 交互的操作，都会返回一个 NaN，而且 NaN 不能用来比较，下面的代码会崩溃：\n",
    "\n",
    "fn main() {\n",
    "  let x = (-42.0_f32).sqrt();\n",
    "  assert_eq!(x, x);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "未定义的数学行为\n"
     ]
    }
   ],
   "source": [
    "// 出于防御性编程的考虑，可以使用 is_nan() 等方法，可以用来判断一个数值是否是 NaN ：\n",
    "\n",
    "fn main() {\n",
    "    let x = (-42.0_f32).sqrt();\n",
    "    if x.is_nan() {\n",
    "        println!(\"未定义的数学行为\")\n",
    "    }\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 数字运算\n",
    "\n",
    "Rust 支持所有数字类型的基本数学运算：加法、减法、乘法、除法和取模运算。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    // 加法\n",
    "    let sum = 5 + 10;\n",
    "\n",
    "    // 减法\n",
    "    let difference = 95.5 - 4.3;\n",
    "\n",
    "    // 乘法\n",
    "    let product = 4 * 30;\n",
    "\n",
    "    // 除法\n",
    "    let quotient = 56.7 / 32.2;\n",
    "\n",
    "    // 求余\n",
    "    let remainder = 43 % 5;\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这些语句中的每个表达式都使用了数学运算符，并且计算结果为一个值，然后绑定到一个变量上。[附录 B](https://course.rs/appendix/operators.html#运算符) 中给出了 Rust 提供的所有运算符的列表。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "20 + 21 + 22 = 63\n",
      "1000000000000\n",
      "42.00\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "  // 编译器会进行自动推导，给予twenty i32的类型\n",
    "  let twenty = 20;\n",
    "  // 类型标注\n",
    "  let twenty_one: i32 = 21;\n",
    "  // 通过类型后缀的方式进行类型标注：22是i32类型\n",
    "  let twenty_two = 22i32;\n",
    "\n",
    "  // 只有同样类型，才能运算\n",
    "  let addition = twenty + twenty_one + twenty_two;\n",
    "  println!(\"{} + {} + {} = {}\", twenty, twenty_one, twenty_two, addition);\n",
    "\n",
    "  // 对于较长的数字，可以用_进行分割，提升可读性\n",
    "  let one_million: i64 = 1_000_000;\n",
    "  println!(\"{}\", one_million.pow(2));\n",
    "\n",
    "  // 定义一个f32数组，其中42.0会自动被推导为f32类型\n",
    "  let forty_twos = [\n",
    "    42.0,\n",
    "    42f32,\n",
    "    42.0_f32,\n",
    "  ];\n",
    "\n",
    "  // 打印数组中第一个值，并控制小数位为2位\n",
    "  println!(\"{:.2}\", forty_twos[0]);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 位运算\n",
    "\n",
    "Rust 的位运算基本上和其他语言一样\n",
    "\n",
    "| 运算符  | 说明                                                   |\n",
    "| ------- | ------------------------------------------------------ |\n",
    "| & 位与  | 相同位置均为1时则为1，否则为0                          |\n",
    "| \\| 位或 | 相同位置只要有1时则为1，否则为0                        |\n",
    "| ^ 异或  | 相同位置不相同则为1，相同则为0                         |\n",
    "| ! 位非  | 把位中的0和1相互取反，即0置为1，1置为0                 |\n",
    "| << 左移 | 所有位向左移动指定位数，右位补0                        |\n",
    "| >> 右移 | 所有位向右移动指定位数，带符号移动（正数补0，负数补1） |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a value is        00000010\n",
      "b value is        00000011\n",
      "(a & b) value is  00000010\n",
      "(a | b) value is  00000011\n",
      "(a ^ b) value is  00000001\n",
      "(!b) value is     11111100\n",
      "(a << b) value is 00010000\n",
      "(a >> b) value is 00000000\n",
      "(a << b) value is 00010000\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    // 无符号8位整数，二进制为00000010\n",
    "    let a: u8 = 2; // 也可以写 let a: u8 = 0b_0000_0010;\n",
    "\n",
    "    // 二进制为00000011\n",
    "    let b: u8 = 3;\n",
    "\n",
    "    // {:08b}：左高右低输出二进制01，不足8位则高位补0\n",
    "    println!(\"a value is        {:08b}\", a);\n",
    "\n",
    "    println!(\"b value is        {:08b}\", b);\n",
    "\n",
    "    println!(\"(a & b) value is  {:08b}\", a & b);\n",
    "\n",
    "    println!(\"(a | b) value is  {:08b}\", a | b);\n",
    "\n",
    "    println!(\"(a ^ b) value is  {:08b}\", a ^ b);\n",
    "\n",
    "    println!(\"(!b) value is     {:08b}\", !b);\n",
    "\n",
    "    println!(\"(a << b) value is {:08b}\", a << b);\n",
    "\n",
    "    println!(\"(a >> b) value is {:08b}\", a >> b);\n",
    "\n",
    "    let mut a = a;\n",
    "    // 注意这些计算符除了!之外都可以加上=进行赋值 (因为!=要用来判断不等于)\n",
    "    a <<= b;\n",
    "    println!(\"(a << b) value is {:08b}\", a);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Rust 在任意构建模式下都会拒绝超出位宽的移位操作，因为移位超界通常意味着逻辑错误，与直接写常量等效，因此一旦超出就立即触发溢出错误。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "let a: u8 = 255;\n",
    "let b = a>>7; // ok\n",
    "let b = a<<7; // ok"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "this arithmetic operation will overflow",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[arithmetic_overflow] Error:\u001b[0m this arithmetic operation will overflow",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_10:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54m>\u001b[0m\u001b[38;5;54m>\u001b[0m\u001b[38;5;54m8\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mw\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m           \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m attempt to shift right by `8_i32`, which would overflow",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let b = a>>8; // overflow"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "this arithmetic operation will overflow",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[arithmetic_overflow] Error:\u001b[0m this arithmetic operation will overflow",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_11:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54m<\u001b[0m\u001b[38;5;54m<\u001b[0m\u001b[38;5;54m8\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mw\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m           \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m attempt to shift left by `8_i32`, which would overflow",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let b = a<<8; // overflow"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 序列(Range)\n",
    "\n",
    "Rust 提供了一个非常简洁的方式，用来生成连续的数值，例如 1..5，生成从 1 到 4 的连续数字，不包含 5 ；`1..=5`，生成从 1 到 5 的连续数字，包含 5，它的用途很简单，常常用于循环中："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "for i in 1..=5 {\n",
    "    println!(\"{}\",i);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "序列只允许用于数字或字符类型，原因是：它们可以连续，同时编译器在编译期可以检查该序列是否为空，字符和数字值是 Rust 中仅有的可以用于判断是否为空的类型。如下是一个使用字符类型序列的例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in 'a'..='z' {\n",
    "    println!(\"{}\",i);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用 As 完成类型转换\n",
    "\n",
    "Rust 中可以使用 As 来完成一个类型到另一个类型的转换，其最常用于将原始类型转换为其他原始类型，但是它也可以完成诸如将指针转换为地址、地址转换为指针以及将指针转换为其他指针等功能。你可以在[这里](https://course.rs/advance/into-types/converse.html)了解更多相关的知识。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 有理数和复数\n",
    "\n",
    "Rust 的标准库相比其它语言，准入门槛较高，因此有理数和复数并未包含在标准库中：\n",
    "\n",
    "- 有理数和复数\n",
    "- 任意大小的整数和任意精度的浮点数\n",
    "- 固定精度的十进制小数，常用于货币相关的场景\n",
    "\n",
    "好在社区已经开发出高质量的 Rust 数值库：[num](https://crates.io/crates/num)。\n",
    "\n",
    "按照以下步骤来引入 `num` 库：\n",
    "\n",
    "1. 创建新工程 `cargo new complex-num && cd complex-num`\n",
    "2. 在 `Cargo.toml` 中的 `[dependencies]` 下添加一行 `num = \"0.4.0\"`\n",
    "3. 将 `src/main.rs` 文件中的 `main` 函数替换为下面的代码\n",
    "4. 运行 `cargo run`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "13.2 + 21i\n",
       "   Compiling num-traits v0.2.19\n",
       "   Compiling num-integer v0.1.46\n",
       "   Compiling num-complex v0.4.6\n",
       "   Compiling num-bigint v0.4.6\n",
       "   Compiling num-iter v0.1.45\n",
       "   Compiling num-rational v0.4.2\n",
       "   Compiling num v0.4.3\n",
       "   Compiling complex-num v0.1.0 (/mnt/d/dev_learn/learnrustbyai_fk/rust_course/01_intro/variable/complex-num)\n",
       "    Finished `dev` profile [unoptimized + debuginfo] target(s) in 3.26s\n",
       "     Running `target/debug/complex-num`\n"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd variable/complex-num && cargo run"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 总结\n",
    "\n",
    "- **Rust 拥有相当多的数值类型**. 因此你需要熟悉这些类型所占用的字节数，这样就知道该类型允许的大小范围以及你选择的类型是否能表达负数\n",
    "- **类型转换必须是显式的**. Rust 永远也不会偷偷把你的 16bit 整数转换成 32bit 整数\n",
    "- **Rust 的数值上可以使用方法**. 例如你可以用以下方法来将 `13.14` 取整：`13.14_f32.round()`，在这里我们使用了类型后缀，因为编译器需要知道 `13.14` 的具体类型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 字符、布尔、单元类型\n",
    "\n",
    "- https://course.rs/basic/base-type/char-bool.html\n",
    "- https://practice-zh.course.rs/basic-types/char-bool-unit.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/basic-types/char-bool.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 字符类型(char)\n",
    "\n",
    "Rust 的字符类型以 4 字节存储任意 Unicode 标量值，因此单个汉字、字母或表情都能用单引号表示。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let c = 'z';\n",
    "    let z = 'ℤ';\n",
    "    let g = '国';\n",
    "    let heart_eyed_cat = '😻';\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "字符'中'占用了4字节的内存大小\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let x = '中';\n",
    "    println!(\"字符'中'占用了{}字节的内存大小\", size_of_val(&x));\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 布尔(bool)\n",
    "\n",
    "Rust 中的布尔类型有两个可能的值：`true` 和 `false`，布尔值占用内存的大小为 1 个字节："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let t = true;\n",
    "\n",
    "    let f: bool = false; // 使用类型标注,显式指定f的类型\n",
    "\n",
    "    if f {\n",
    "        println!(\"这是段毫无意义的代码\");\n",
    "    }\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 单元类型(unit)\n",
    "\n",
    "Rust 的单元类型 `()` 只有一个同名值，常作为函数默认返回值（如 `main`、`println!`），也可用来占位表示“无关值”而且不占内存\n",
    "> 和 Go 语言的 `struct{}` 类似，可以作为一个值用来占位，但是完全不占用任何内存"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 语句和表达式\n",
    "\n",
    "- https://course.rs/basic/base-type/statement-expression.html\n",
    "- https://practice-zh.course.rs/basic-types/statements-expressions.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/basic-types/statements.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Rust 的函数体是由一系列语句组成，最后由一个表达式来返回值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn add_with_extra(x: i32, y: i32) -> i32 {\n",
    "    let x = x + 1; // 语句\n",
    "    let y = y + 5; // 语句\n",
    "    x + y // 表达式\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 语句"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "let a = 8;\n",
    "let b: Vec<f64> = Vec::new();\n",
    "let (a, c) = (\"hi\", false);\n",
    "// 以上都是语句，它们完成了一个具体的操作，但是并没有返回值，因此是语句。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "expected expression, found `let` statement",
     "output_type": "error",
     "traceback": [
      "let b = (let a = 8);",
      "\u001b[91m         ^^^\u001b[0m \u001b[94merror: expected expression, found `let` statement\u001b[0m",
      "expected expression, found `let` statement"
     ]
    },
    {
     "ename": "Error",
     "evalue": "unnecessary parentheses around assigned value",
     "output_type": "error",
     "traceback": [
      "unnecessary parentheses around assigned value",
      "\u001b[1mhelp\u001b[0m: remove these parentheses\n\n"
     ]
    },
    {
     "ename": "Error",
     "evalue": "unused variable: `t`",
     "output_type": "error",
     "traceback": [
      "warning: unused variable: `t`",
      "unused variable: `t`",
      "\u001b[1mhelp\u001b[0m: if this is intentional, prefix it with an underscore\n\n_t"
     ]
    }
   ],
   "source": [
    "// 由于 let 是语句，因此不能将 let 语句赋值给其它值，如下形式是错误的：\n",
    "let b = (let a = 8);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 表达式\n",
    "\n",
    "表达式会进行求值，然后返回一个值。\n",
    "\n",
    "调用一个函数是表达式，因为会返回一个值，调用宏也是表达式，用花括号包裹最终返回一个值的语句块也是表达式，总之，能返回值，它就是表达式:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The value of y is: 4\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let y = {\n",
    "        let x = 3;\n",
    "        x + 1\n",
    "    };\n",
    "\n",
    "    println!(\"The value of y is: {}\", y);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let x = 3;\n",
    "    x + 1\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 表达式如果不返回任何值，会隐式地返回一个 () \n",
    "\n",
    "fn ret_unit_type() {\n",
    "    let x = 1;\n",
    "    // if 语句块也是一个表达式，因此可以用于赋值，也可以直接返回\n",
    "    // 类似三元运算符，在Rust里我们可以这样写\n",
    "    let y = if x % 2 == 1 {\n",
    "        \"odd\"\n",
    "    } else {\n",
    "        \"even\"\n",
    "    };\n",
    "    // 或者写成一行\n",
    "    let z = if x % 2 == 1 { \"odd\" } else { \"even\" };\n",
    "}\n",
    "\n",
    "assert_eq!(ret_unit_type(), ())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn add(i: i32, j: i32) -> i32 {\n",
    "   i + j\n",
    "}"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "fn add(i: i32, j: i32) -> i32 {\n",
    "│  │   │  │    │  │       │   │\n",
    "│  │   │  │    │  │       │   └─ Begin code block\n",
    "│  │   │  │    │  │       └─ Return type\n",
    "│  │   │  │    │  └─ Type\n",
    "│  │   │  │    └─ Identifier\n",
    "│  │   │  └─ Type\n",
    "│  │   └─ Identifier\n",
    "│  └─ Function identifier\n",
    "└─ Keyword\n",
    "\n",
    "         Parameters"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数要点\n",
    "\n",
    "- 函数名和变量名使用[蛇形命名法(snake case)](https://course.rs/practice/naming.html)，例如 `fn add_two() {}`\n",
    "- 函数的位置可以随便放，Rust 不关心我们在哪里定义了函数，只要有定义即可\n",
    "- 每个函数参数都需要标注类型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The value of x is: 5\n",
      "The value of y is: 6.1\n"
     ]
    }
   ],
   "source": [
    "// Rust 是静态类型语言，因此需要你为每一个函数参数都标识出它的具体类型\n",
    "fn another_function(x: i32, y: f32) {\n",
    "    println!(\"The value of x is: {}\", x);\n",
    "    println!(\"The value of y is: {}\", y);\n",
    "}\n",
    "\n",
    "another_function(5, 6.1);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "expected one of `:`, `@`, or `|`, found `)`",
     "output_type": "error",
     "traceback": [
      "\u001b[31mError:\u001b[0m expected one of `:`, `@`, or `|`, found `)`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_29:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                             \u001b[38;5;68m│\u001b[0m\u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                             \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m help: if this is a type, explicitly ignore the parameter name: `_: `",
      " \u001b[38;5;240m  │\u001b[0m                              \u001b[38;5;54m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                              \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected one of `:`, `@`, or `|`",
      " \u001b[38;5;240m  │\u001b[0m                              \u001b[38;5;100m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                              \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m help: if this is a parameter name, give it a type: `: TypeName`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "unused variable: `y`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[unused_variables] Error:\u001b[0m unused variable: `y`"
     ]
    },
    {
     "ename": "Error",
     "evalue": "unused variable: `z`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[unused_variables] Error:\u001b[0m unused variable: `z`"
     ]
    }
   ],
   "source": [
    "fn another_function(x: i32, y) {\n",
    "    println!(\"The value of x is: {}\", x);\n",
    "    println!(\"The value of y is: {}\", y);\n",
    "}\n",
    "\n",
    "another_function(5, 6.1);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数返回\n",
    "\n",
    "函数的返回值就是函数体最后一条表达式的返回值，当然我们也可以使用 `return` 提前返回"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The value of x is: 10\n"
     ]
    }
   ],
   "source": [
    "fn plus_five(x:i32) -> i32 {\n",
    "    x + 5 // x + 5 是一条表达式，求值后，返回一个值，因为它是函数的最后一行，因此该表达式的值也是函数的返回值。\n",
    "}\n",
    "\n",
    "let x = plus_five(5); // 在 Rust 中函数也是表达式. 写法等同于 let x = 5 + 5;\n",
    "\n",
    "println!(\"The value of x is: {}\", x);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The value of x is: 10\n"
     ]
    }
   ],
   "source": [
    "fn plus_or_minus(x:i32) -> i32 {\n",
    "    if x > 5 {\n",
    "        return x - 5\n",
    "    }\n",
    "\n",
    "    x + 5\n",
    "}\n",
    "\n",
    "\n",
    "let x = plus_or_minus(5);\n",
    "\n",
    "println!(\"The value of x is: {}\", x);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Rust 中的特殊返回类型\n",
    "\n",
    "**无返回值()**\n",
    "\n",
    "单元类型 `()`，是一个零长度的元组\n",
    "- 函数没有返回值，那么返回一个 `()`\n",
    "- 通过 `;` 结尾的语句返回一个 `()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fmt::Debug;\n",
    "\n",
    "// 隐式返回一个 ()\n",
    "fn report<T: Debug>(item: T) {\n",
    "  println!(\"{:?}\", item);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 函数显式的返回了 ()\n",
    "fn clear(text: &mut String) -> () {\n",
    "  *text = String::from(\"\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "mismatched types",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0308] Error:\u001b[0m mismatched types",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_33:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100ma\u001b[0m\u001b[38;5;100md\u001b[0m\u001b[38;5;100md\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54m3\u001b[0m\u001b[38;5;54m2\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m    \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m                 \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m implicitly returns `()` as its body has no tail or `return` expression",
      " \u001b[38;5;240m  │\u001b[0m                         \u001b[38;5;54m│\u001b[0m   ",
      " \u001b[38;5;240m  │\u001b[0m                         \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected `u32`, found `()`",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m+\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;68m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;68m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m help: remove this semicolon to return this value: ``",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "unused variable: `y`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[unused_variables] Error:\u001b[0m unused variable: `y`"
     ]
    },
    {
     "ename": "Error",
     "evalue": "unused variable: `z`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[unused_variables] Error:\u001b[0m unused variable: `z`"
     ]
    }
   ],
   "source": [
    "fn add(x:u32,y:u32) -> u32 {\n",
    "    x + y; // 只有表达式能返回值，而 ; 结尾的是语句\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**永不返回的发散函数 !**\n",
    "- 当用 `!` 作函数返回类型的时候，表示该函数永不返回( diverging functions )，特别的，这种语法往往用做会导致程序崩溃的函数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:34:3:\n",
      "你已经到了穷途末路，崩溃吧！\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: <unknown>\n",
      "   3: <unknown>\n",
      "   4: <unknown>\n",
      "   5: <unknown>\n",
      "   6: evcxr::runtime::Runtime::run_loop\n",
      "   7: evcxr::runtime::runtime_hook\n",
      "   8: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "fn dead_end() -> ! {\n",
    "  panic!(\"你已经到了穷途末路，崩溃吧！\");\n",
    "}\n",
    "\n",
    "dead_end();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 下面的函数创建了一个无限循环，该循环永不跳出，因此函数也永不返回：\n",
    "\n",
    "fn forever() -> ! {\n",
    "  loop {\n",
    "    //...\n",
    "  };\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.4. 复合类型 / Compound Types"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "复合类型通过把相关数据与操作打包成 `struct` 或 `enum`，使诸如文件操作这类代码得到更高层次的抽象与管理，而掌握 `String` 与 `&str` 的所有权语义正是迈向这一阶段的基础。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "#![allow(unused_variables)]\n",
    "type File = String;\n",
    "\n",
    "fn open(f: &mut File) -> bool {\n",
    "    true\n",
    "}\n",
    "fn close(f: &mut File) -> bool {\n",
    "    true\n",
    "}\n",
    "\n",
    "#[allow(dead_code)]\n",
    "fn read(f: &mut File, save_to: &mut Vec<u8>) -> ! {\n",
    "    unimplemented!()\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let mut f1 = File::from(\"f1.txt\");\n",
    "    open(&mut f1);\n",
    "    //read(&mut f1, &mut vec![]);\n",
    "    close(&mut f1);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `#![allow(unused_variables)]` 属性标记: 该标记会告诉编译器忽略未使用的变量，不要抛出 `warning` 警告，具体的常见编译器属性你可以在这里查阅：[编译器属性标记](https://course.rs/profiling/compiler/attributes.html)。\n",
    "- `unimplemented!() `: `read` 函数也非常有趣，它返回一个 `!` 类型，这个表明该函数是一个发散函数，不会返回任何值，包括 `()`。`unimplemented!()` 告诉编译器该函数尚未实现，`unimplemented!()` 标记通常意味着我们期望快速完成主要代码，回头再通过搜索这些标记来完成次要代码，类似的标记还有 `todo!()`，当代码执行到这种未实现的地方时，程序会直接报错。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:16:5:\n",
      "not implemented\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: core::panicking::panic\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:145:5\n",
      "   3: ctx::read\n",
      "   4: ctx::main\n",
      "   5: run_user_code_2\n",
      "   6: evcxr::runtime::Runtime::run_loop\n",
      "   7: evcxr::runtime::runtime_hook\n",
      "   8: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "#![allow(unused_variables)]\n",
    "type File = String;\n",
    "\n",
    "fn open(f: &mut File) -> bool {\n",
    "    true\n",
    "}\n",
    "fn close(f: &mut File) -> bool {\n",
    "    true\n",
    "}\n",
    "\n",
    "#[allow(dead_code)]\n",
    "fn read(f: &mut File, save_to: &mut Vec<u8>) -> ! {\n",
    "    unimplemented!()\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let mut f1 = File::from(\"f1.txt\");\n",
    "    open(&mut f1);\n",
    "    read(&mut f1, &mut vec![]);\n",
    "    close(&mut f1);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 字符串与切片 / String, Slice\n",
    "\n",
    "- https://course.rs/basic/compound-type/string-slice.html\n",
    "- https://practice-zh.course.rs/compound-types/string.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/compound-types/string.md\n",
    "- https://practice-zh.course.rs/compound-types/slice.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/compound-types/slice.md\n",
    "- https://practice-zh.course.rs/collections/string.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/collections/String.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 字符串"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "mismatched types",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0308] Error:\u001b[0m mismatched types",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_7:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mg\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54my\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m   \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;68m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m arguments to this function are incorrect",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;54m│\u001b[0m   \u001b[38;5;68m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected `String`, found `&str`",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;68m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m help: try using a conversion method: `.to_string()`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "  let my_name = \"Pascal\";\n",
    "  greet(my_name);\n",
    "}\n",
    "\n",
    "fn greet(name: String) {\n",
    "  println!(\"Hello, {}!\", name);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, Pascal!\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "  let my_name = \"Pascal\";\n",
    "  greet(my_name.to_string());\n",
    "}\n",
    "\n",
    "fn greet(name: String) {\n",
    "  println!(\"Hello, {}!\", name);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 切片(slice)\n",
    "\n",
    "Rust 的字符串切片通过左闭右开的索引引用 UTF-8 字符边界内的部分数据，并在编译期借用检查中防止同时存在的可变与不可变引用错误。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "  let s = String::from(\"hello world\");\n",
    "\n",
    "  let hello = &s[0..5];\n",
    "  let world = &s[6..11];\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "  let s = String::from(\"hello\");\n",
    "\n",
    "  let slice = &s[0..2];\n",
    "  let slice = &s[..2]; // 两个是等效\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 切片想要包含 String 的最后一个字节\n",
    "{\n",
    "  let s = String::from(\"hello\");\n",
    "\n",
    "  let len = s.len();\n",
    "\n",
    "  let slice = &s[4..len];\n",
    "  let slice = &s[4..];\n",
    "  }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 截取完整的 String 切片\n",
    "{\n",
    "let s = String::from(\"hello\");\n",
    "\n",
    "let len = s.len();\n",
    "\n",
    "let slice = &s[0..len];\n",
    "let slice = &s[..];\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:24:13:\n",
      "byte index 2 is not a char boundary; it is inside '中' (bytes 0..3) of `中国人`\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: core::str::slice_error_fail_rt\n",
      "   3: core::str::slice_error_fail\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/str/mod.rs:69:5\n",
      "   4: __rust_try.llvm.7787680985361894855\n",
      "   5: std::panic::catch_unwind\n",
      "   6: run_user_code_5\n",
      "   7: evcxr::runtime::Runtime::run_loop\n",
      "   8: evcxr::runtime::runtime_hook\n",
      "   9: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "  let s = \"中国人\";\n",
    "  let a = &s[0..2];\n",
    "  println!(\"{}\",a);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "中\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "  let s = \"中国人\";\n",
    "  let a = &s[0..3];\n",
    "  println!(\"{}\",a);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot borrow `s` as mutable because it is also borrowed as immutable",
     "output_type": "error",
     "traceback": [
      "    s.clear(); // error!",
      "\u001b[91m    ^^^^^^^^^\u001b[0m \u001b[94mmutable borrow occurs here\u001b[0m",
      "    let word = first_word(&s);",
      "\u001b[91m                          ^^\u001b[0m \u001b[94mimmutable borrow occurs here\u001b[0m",
      "    println!(\"the first word is: {}\", word);",
      "\u001b[91m                                      ^^^^\u001b[0m \u001b[94mimmutable borrow later used here\u001b[0m",
      "cannot borrow `s` as mutable because it is also borrowed as immutable"
     ]
    }
   ],
   "source": [
    "// 当我们已经有了可变借用时，就无法再拥有不可变的借用\n",
    "fn main() {\n",
    "    let mut s = String::from(\"hello world\");\n",
    "\n",
    "    let word = first_word(&s);\n",
    "\n",
    "    s.clear(); // error!\n",
    "\n",
    "    println!(\"the first word is: {}\", word);\n",
    "}\n",
    "\n",
    "// 输入 String 类型，返回它的切片\n",
    "fn first_word(s: &String) -> &str {\n",
    "    &s[..1]\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**其它切片**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "  let a = [1, 2, 3, 4, 5]; // 数组\n",
    "\n",
    "  let slice = &a[1..3];\n",
    "\n",
    "  assert_eq!(slice, &[2, 3]);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 字符串字面量是切片"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let s = \"Hello, world!\"; // s 的类型是 &str"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let s: &str = \"Hello, world!\"; // 该切片指向了程序可执行文件中的某个点，这也是为什么字符串字面量是不可变的，因为 &str 是一个不可变引用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 什么是字符串?\n",
    "\n",
    "Rust 中的字符串是 UTF-8 编码的字符序列：语言层面提供只读、不可变的 `str`（通常以借用形式 `&str` 出现），标准库提供可增长、拥有所有权的 `String` 以及其他用途的 `OsString`/`OsStr`、`CString`/`CStr` 等，其中名称以 `String` 结尾的代表拥有所有权，以 `Str` 结尾的代表被借用的视图。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### String 与 &str 的转换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello,world!\n",
      "hello,world!\n",
      "hello,world!\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let s = String::from(\"hello,world!\");\n",
    "    say_hello(&s);\n",
    "    say_hello(&s[..]);\n",
    "    say_hello(s.as_str());\n",
    "}\n",
    "\n",
    "// 将 String 类型转为 &str 类型\n",
    "fn say_hello(s: &str) {\n",
    "    println!(\"{}\",s);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "实际上这种灵活用法是因为 `deref` 隐式强制转换，具体我们会在 [`Deref` 特征](https://course.rs/advance/smart-pointer/deref.html)进行详细讲解"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 字符串索引\n",
    "\n",
    "在其它语言中，使用索引的方式访问字符串的某个字符或者子串是很正常的行为，但是在 Rust 中就会报错："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "consider importing this trait",
     "output_type": "error",
     "traceback": [
      "\u001b[31mError:\u001b[0m consider importing this trait"
     ]
    },
    {
     "ename": "Error",
     "evalue": "the type `str` cannot be indexed by `{integer}`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m the type `str` cannot be indexed by `{integer}`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_6:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m[\u001b[0m\u001b[38;5;54m0\u001b[0m\u001b[38;5;249m]\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m string indices are ranges of `usize`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let s1 = String::from(\"hello\");\n",
    "let h = s1[0];"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**深入字符串内部**\n",
    "\n",
    "`let hello = String::from(\"Hola\");`:\n",
    "- `String` 底层实际存放的是 `u8` 字节数组，所以 `\"Hola\"` 占 4 个字节（每个字符 1 字节），而 `\"中国人\"` 占 9 个字节（每个汉字 3 字节）；因此直接对 UTF-8 字符串按字节索引会落在字符中间，得到的只是单个字节而非完整字符，既不直观也不安全。\n",
    "\n",
    "**字符串的不同表现形式**\n",
    "- Rust 的 UTF-8 字符串底层是 `u8` 数组，可按字节、Unicode 标量或字素簇多种方式观察；由于字符宽度可变且定位合法字符可能需线性扫描，索引操作既容易落在字符中间又难以做到 O(1)，因此被禁止。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 用梵文写的字符串 “नमस्ते”, 它底层的字节数组如下形式\n",
    "\n",
    "[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164,\n",
    "224, 165, 135]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 长度是 18 个字节，这也是计算机最终存储该字符串的形式。如果从字符的形式去看，则是\n",
    "\n",
    "['न', 'म', 'स', '्', 'त', 'े']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 但是这种形式下，第四和六两个字母根本就不存在，没有任何意义，接着再从字母串的形式去看：\n",
    "\n",
    "[\"न\", \"म\", \"स्\", \"ते\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 字符串切片\n",
    "\n",
    "字符串切片按字节索引 UTF-8 数据，若区间落在字符内部会触发运行时崩溃，因此必须谨慎使用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:109:15:\n",
      "byte index 2 is not a char boundary; it is inside '中' (bytes 0..3) of `中国人`\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: core::str::slice_error_fail_rt\n",
      "   3: core::str::slice_error_fail\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/str/mod.rs:69:5\n",
      "   4: <unknown>\n",
      "   5: <unknown>\n",
      "   6: <unknown>\n",
      "   7: evcxr::runtime::Runtime::run_loop\n",
      "   8: evcxr::runtime::runtime_hook\n",
      "   9: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "let hello = \"中国人\";\n",
    "\n",
    "let s = &hello[0..2];"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 操作字符串\n",
    "\n",
    "由于 `String` 是可变字符串，下面介绍 Rust 字符串的修改，添加，删除等常用方法："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**追加 (Push)**\n",
    "- 在字符串尾部可以使用 `push()` 方法追加字符 `char`，也可以使用 `push_str()` 方法追加字符串字面量。这两个方法都是**在原有的字符串上追加，并不会返回新的字符串**。由于字符串追加操作要修改原来的字符串，则该字符串必须是可变的，即**字符串变量必须由 `mut` 关键字修饰**。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "追加字符串 push_str() -> Hello rust\n",
      "追加字符 push() -> Hello rust!\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let mut s = String::from(\"Hello \");\n",
    "\n",
    "    s.push_str(\"rust\");\n",
    "    println!(\"追加字符串 push_str() -> {}\", s);\n",
    "\n",
    "    s.push('!');\n",
    "    println!(\"追加字符 push() -> {}\", s);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**插入 (Insert)**\n",
    "- 可以使用 `insert()` 方法插入单个字符 `char`，也可以使用 `insert_str()` 方法插入字符串字面量，与 `push()` 方法不同，这俩方法需要传入两个参数，第一个参数是字符（串）插入位置的索引，第二个参数是要插入的字符（串），索引从 0 开始计数，如果越界则会发生错误。由于字符串插入操作要**修改原来的字符串**，则该字符串必须是可变的，即**字符串变量必须由 `mut` 关键字修饰*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "插入字符 insert() -> Hello, rust!\n",
      "插入字符串 insert_str() -> Hello, I like rust!\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let mut s = String::from(\"Hello rust!\");\n",
    "    s.insert(5, ',');\n",
    "    println!(\"插入字符 insert() -> {}\", s);\n",
    "    s.insert_str(6, \" I like\");\n",
    "    println!(\"插入字符串 insert_str() -> {}\", s);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**替换 (Replace)**\n",
    "- 如果想要把字符串中的某个字符串替换成其它的字符串，那可以使用 `replace()` 方法。与替换有关的方法有三个。\n",
    "\n",
    "| 方法            | 适用类型          | 参数                                                         | 行为描述                                         | 是否返回新字符串 |\n",
    "| --------------- | ----------------- | ------------------------------------------------------------ | ------------------------------------------------ | ---------------- |\n",
    "| `replace`       | `String` / `&str` | `pattern`: 要被替换的字符串<br>`replacement`: 新字符串       | 替换所有匹配的子串                               | ✅ 是             |\n",
    "| `replacen`      | `String` / `&str` | `pattern`: 要被替换的字符串<br>`replacement`: 新字符串<br>`count`: 最大替换次数 | 最多替换指定数量的匹配子串                       | ✅ 是             |\n",
    "| `replace_range` | `String`          | `range`: 要替换的字节范围（`Range`）<br>`replace_with`: 新字符串 | 直接在原字符串中用新内容替换指定范围（需 `mut`） | ❌ 否（原地修改） |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[src/lib.rs:10:5] new_string_replace = \"I like RUST. Learning RUST is my favorite!\"\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let string_replace = String::from(\"I like rust. Learning rust is my favorite!\");\n",
    "    let new_string_replace = string_replace.replace(\"rust\", \"RUST\");\n",
    "    dbg!(new_string_replace);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[src/lib.rs:10:5] new_string_replacen = \"I like RUST. Learning rust is my favorite!\"\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let string_replace = \"I like rust. Learning rust is my favorite!\";\n",
    "    let new_string_replacen = string_replace.replacen(\"rust\", \"RUST\", 1);\n",
    "    dbg!(new_string_replacen);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[src/lib.rs:10:5] string_replace_range = \"I like Rust!\"\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let mut string_replace_range = String::from(\"I like rust!\");\n",
    "    string_replace_range.replace_range(7..8, \"R\");\n",
    "    dbg!(string_replace_range);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**删除 (Delete)**\n",
    "\n",
    "| 方法         | 作用范围 | 行为描述                                 | 返回值                          | 字节边界限制  |\n",
    "| ------------ | -------- | ---------------------------------------- | ------------------------------- | ------------- |\n",
    "| `pop()`      | `String` | 删除最后一个字符并返回它，原地修改字符串 | `Option<char>`（空串时 `None`） | ❌（隐式确保） |\n",
    "| `remove()`   | `String` | 删除指定**字符起始索引**处的字符并返回   | `char`                          | ✅ 必须合法    |\n",
    "| `truncate()` | `String` | 从给定索引开始截断到结尾，保留前半部分   | `()`                            | ✅ 必须合法    |\n",
    "| `clear()`    | `String` | 清空字符串内容，相当于 `truncate(0)`     | `()`                            | —             |\n",
    "\n",
    "> 注意：`remove()` 与 `truncate()` 的索引按字节计算，必须落在合法的 UTF-8 字符边界，否则会触发运行时错误。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[src/lib.rs:6:5] p1 = Some(\n",
      "    '!',\n",
      ")\n",
      "[src/lib.rs:7:5] p2 = Some(\n",
      "    '文',\n",
      ")\n",
      "[src/lib.rs:8:5] string_pop = \"rust pop 中\"\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let mut string_pop = String::from(\"rust pop 中文!\");\n",
    "    let p1 = string_pop.pop();\n",
    "    let p2 = string_pop.pop();\n",
    "    dbg!(p1);\n",
    "    dbg!(p2);\n",
    "    dbg!(string_pop);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "string_remove 占 18 个字节\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[src/lib.rs:14:5] string_remove = \"试remove方法\"\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let mut string_remove = String::from(\"测试remove方法\");\n",
    "    println!(\n",
    "        \"string_remove 占 {} 个字节\",\n",
    "        std::mem::size_of_val(string_remove.as_str())\n",
    "    );\n",
    "    // 删除第一个汉字\n",
    "    string_remove.remove(0);\n",
    "    // 下面代码会发生错误\n",
    "    // string_remove.remove(1);\n",
    "    // 直接删除第二个汉字\n",
    "    // string_remove.remove(3);\n",
    "    dbg!(string_remove);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[src/lib.rs:5:5] string_truncate = \"测\"\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let mut string_truncate = String::from(\"测试truncate\");\n",
    "    string_truncate.truncate(3);\n",
    "    dbg!(string_truncate);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[src/lib.rs:5:5] string_clear = \"\"\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let mut string_clear = String::from(\"string clear\");\n",
    "    string_clear.clear();\n",
    "    dbg!(string_clear);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**连接 (Concatenate)**\n",
    "\n",
    "| 方法/操作    | 适用类型                                       | 基本用法示例                                 | 是否要求可变 (`mut`) | 所有权/借用状况                                              | 返回值类型 | 备注与特征                                                   |\n",
    "| ------------ | ---------------------------------------------- | -------------------------------------------- | -------------------- | ------------------------------------------------------------ | ---------- | ------------------------------------------------------------ |\n",
    "| `+` 运算符   | `String` + `&str`（或 `&String` 自动解引用）   | `let result = string_append + &string_rust;` | 左操作数无需 `mut`   | 左操作数（`String`）的所有权会被移动；右操作数必须是 `&str`（会被借用） | `String`   | 等价于 `String::add(self, &str)`；可链式连接：`String + &str + &str ...` |\n",
    "| `+=` 运算符  | `String` += `&str`                             | `result += \"!!!\";`                           | ✅ 需要 `mut`         | 左操作数为可变 `String`，所有权保留；右操作数为 `&str`（借用） | `()`       | 在原字符串上就地追加内容；与 `push_str` 行为类似。           |\n",
    "| `format!` 宏 | 支持 `String` / `&str` 等实现 `Display` 的类型 | `let s = format!(\"{} {}!\", s1, s2);`         | 不要求 `mut`         | 所有参数按所有权传入（`String` 会被移动，字面量/引用按借用）；结果是新 `String` | `String`   | 与 `println!` 类似的格式化语法；不会修改原字符串；可灵活组合多种类型和格式控制。 |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "连接字符串 + -> hello rust!!!!\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let string_append = String::from(\"hello \");\n",
    "    let string_rust = String::from(\"rust\");\n",
    "    // &string_rust会自动解引用为&str\n",
    "    let result = string_append + &string_rust;\n",
    "    let mut result = result + \"!\"; // `result + \"!\"` 中的 `result` 是不可变的\n",
    "    result += \"!!!\";\n",
    "\n",
    "    println!(\"连接字符串 + -> {}\", result);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let s1 = String::from(\"hello,\");\n",
    "    let s2 = String::from(\"world!\");\n",
    "    // 在下句中，s1的所有权被转移走了，因此后面不能再使用s1\n",
    "    let s3 = s1 + &s2;\n",
    "    assert_eq!(s3,\"hello,world!\");\n",
    "    // 下面的语句如果去掉注释，就会报错\n",
    "    // println!(\"{}\",s1);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let s1 = String::from(\"tic\");\n",
    "let s2 = String::from(\"tac\");\n",
    "let s3 = String::from(\"toe\");\n",
    "\n",
    "// String = String + &str + &str + &str + &str\n",
    "let s = s1 + \"-\" + &s2 + \"-\" + &s3;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "详见[格式化输出](https://course.rs/basic/formatted-output.html#printprintlnformat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello rust!\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let s1 = \"hello\";\n",
    "    let s2 = String::from(\"rust\");\n",
    "    let s = format!(\"{} {}!\", s1, s2);\n",
    "    println!(\"{}\", s);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 字符串转义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "What are you doing? (\\x3F means ?) I'm writing Rust!\n",
      "Unicode character ℝ (U+211D) is called \"DOUBLE-STRUCK CAPITAL R\"\n",
      "String literals\n",
      "                        can span multiple lines.\n",
      "                        The linebreak and indentation here -><- can be escaped too!\n"
     ]
    }
   ],
   "source": [
    "// 通过转义的方式 \\ 输出 ASCII 和 Unicode 字符\n",
    "\n",
    "fn main() {\n",
    "    // 通过 \\ + 字符的十六进制表示，转义输出一个字符\n",
    "    let byte_escape = \"I'm writing \\x52\\x75\\x73\\x74!\";\n",
    "    println!(\"What are you doing\\x3F (\\\\x3F means ?) {}\", byte_escape);\n",
    "\n",
    "    // \\u 可以输出一个 unicode 字符\n",
    "    let unicode_codepoint = \"\\u{211D}\";\n",
    "    let character_name = \"\\\"DOUBLE-STRUCK CAPITAL R\\\"\";\n",
    "\n",
    "    println!(\n",
    "        \"Unicode character {} (U+211D) is called {}\",\n",
    "        unicode_codepoint, character_name\n",
    "    );\n",
    "\n",
    "    // 换行了也会保持之前的字符串格式\n",
    "    // 使用\\忽略换行符\n",
    "    let long_string = \"String literals\n",
    "                        can span multiple lines.\n",
    "                        The linebreak and indentation here ->\\\n",
    "                        <- can be escaped too!\";\n",
    "    println!(\"{}\", long_string);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 保持字符串的原样，不要转义\n",
    "\n",
    "fn main() {\n",
    "    println!(\"{}\", \"hello \\\\x52\\\\x75\\\\x73\\\\x74\");\n",
    "    let raw_str = r\"Escapes don't work here: \\x3F \\u{211D}\";\n",
    "    println!(\"{}\", raw_str);\n",
    "\n",
    "    // 如果字符串包含双引号，可以在开头和结尾加 #\n",
    "    let quotes = r#\"And then I said: \"There is no escape!\"\"#;\n",
    "    println!(\"{}\", quotes);\n",
    "\n",
    "    // 如果字符串中包含 # 号，可以在开头和结尾加多个 # 号，最多加255个，只需保证与字符串中连续 # 号的个数不超过开头和结尾的 # 号的个数即可\n",
    "    let longer_delimiter = r###\"A string with \"# in it. And even \"##!\"###;\n",
    "    println!(\"{}\", longer_delimiter);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 操作 UTF-8 字符串"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "中\n",
      "国\n",
      "人\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 要以 Unicode 字符的方式遍历字符串，最好的办法是使用 chars 方法\n",
    "\n",
    "for c in \"中国人\".chars() {\n",
    "    println!(\"{}\", c);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "228\n",
      "184\n",
      "173\n",
      "229\n",
      "155\n",
      "189\n",
      "228\n",
      "186\n",
      "186\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 返回字符串的底层字节数组表现形式\n",
    "\n",
    "for b in \"中国人\".bytes() {\n",
    "    println!(\"{}\", b);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**获取子串**\n",
    "- 想要准确的从 UTF-8 字符串中获取子串是较为复杂的事情，例如想要从 `holla中国人नमस्ते` 这种变长的字符串中取出某一个子串，使用标准库你是做不到的。 你需要在 `crates.io` 上搜索 `utf8` 来寻找想要的功能。\n",
    "- 可以考虑尝试下这个库：[utf8_slice](https://crates.io/crates/utf8_slice)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 字符串深度剖析\n",
    "\n",
    "`String` 位于堆上、可增长并在作用域结束时由 Rust 自动调用 `drop` 释放，而编译期内嵌的不可变 `str` 则因静态存储与高效性不可变，这正体现了 Rust 用所有权机制平衡性能与安全。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "{\n",
    "    let s = String::from(\"hello\"); // 从此处起，s 是有效的\n",
    "\n",
    "    // 使用 s\n",
    "}                                  // 此作用域已结束，\n",
    "                                   // s 不再有效，内存被释放\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 元组 / Tuple\n",
    "\n",
    "- https://course.rs/basic/compound-type/tuple.html\n",
    "- https://practice-zh.course.rs/compound-types/tuple.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/compound-types/tuple.md"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 元组是由多种类型组合到一起形成的，因此它是复合类型，元组的长度是固定的，元组中元素的顺序也是固定的。\n",
    "// 可以使用模式匹配或者 . 操作符来获取元组中的值\n",
    "\n",
    "fn main() {\n",
    "    let tup: (i32, f64, u8) = (500, 6.4, 1); // 变量 tup 被绑定了一个元组值 (500, 6.4, 1)，该元组的类型是 (i32, f64, u8)\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**用模式匹配解构元组**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The value of y is: 6.4\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let tup = (500, 6.4, 1); // 元组的索引从 0 开始\n",
    "\n",
    "    let (x, y, z) = tup;\n",
    "\n",
    "    println!(\"The value of y is: {}\", y);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**元组的使用示例**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The length of 'hello' is 5.\n"
     ]
    }
   ],
   "source": [
    "// 元组在函数返回值场景很常用\n",
    "\n",
    "fn main() {\n",
    "    let s1 = String::from(\"hello\");\n",
    "\n",
    "    let (s2, len) = calculate_length(s1);\n",
    "\n",
    "    println!(\"The length of '{}' is {}.\", s2, len);\n",
    "}\n",
    "\n",
    "fn calculate_length(s: String) -> (String, usize) {\n",
    "    let length = s.len(); // len() 返回字符串的长度\n",
    "\n",
    "    (s, length) // 不具备任何清晰的含义\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 结构体\n",
    "\n",
    "- https://course.rs/basic/compound-type/struct.html\n",
    "- https://practice-zh.course.rs/compound-types/struct.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/compound-types/struct.md\n",
    "\n",
    "结构体跟之前讲过的元组有些相像：都是由多种类型组合而成。但是与元组不同的是，结构体可以为内部的每个字段起一个富有含义的名称。因此结构体更加灵活更加强大，你无需依赖这些字段的顺序来访问和解析它们。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 结构体语法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**定义结构体**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct User {\n",
    "    active: bool,\n",
    "    username: String,\n",
    "    email: String,\n",
    "    sign_in_count: u64,\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**创建结构体实例**\n",
    "1. 初始化实例时，**每个字段**都需要进行初始化\n",
    "2. 初始化时的字段顺序**不需要**和结构体定义时的顺序一致"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let user1 = User {\n",
    "    email: String::from(\"someone@example.com\"),\n",
    "    username: String::from(\"someusername123\"),\n",
    "    active: true,\n",
    "    sign_in_count: 1,\n",
    "};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**访问结构体字段**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let mut user1 = User {\n",
    "    email: String::from(\"someone@example.com\"),\n",
    "    username: String::from(\"someusername123\"),\n",
    "    active: true,\n",
    "    sign_in_count: 1,\n",
    "};\n",
    "\n",
    "user1.email = String::from(\"anotheremail@example.com\");\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**简化结构体创建**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn build_user(email: String, username: String) -> User {\n",
    "    User {\n",
    "        email: email,\n",
    "        username: username,\n",
    "        active: true,\n",
    "        sign_in_count: 1,\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn build_user(email: String, username: String) -> User {\n",
    "    User {\n",
    "        email, // 当函数参数和结构体字段同名时，可以直接使用缩略的方式进行初始化\n",
    "        username,\n",
    "        active: true,\n",
    "        sign_in_count: 1,\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**结构体更新语法**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 根据已有的 user1 实例来构建 user2\n",
    "\n",
    "let user2 = User {\n",
    "      active: user1.active,\n",
    "      username: user1.username,\n",
    "      email: String::from(\"another@example.com\"),\n",
    "      sign_in_count: user1.sign_in_count,\n",
    "  };"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 因为 user2 仅仅在 email 上与 user1 不同，因此我们只需要对 email 进行赋值，剩下的通过结构体更新语法 ..user1 即可完成。\n",
    "\n",
    "let user2 = User {\n",
    "      email: String::from(\"another@example.com\"), // \n",
    "      ..user1\n",
    "  };"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "#[derive(Debug)]\n",
    "struct User {\n",
    "    active: bool,\n",
    "    username: String,\n",
    "    email: String,\n",
    "    sign_in_count: u64,\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n"
     ]
    }
   ],
   "source": [
    "// 把结构体中具有所有权的字段转移出去后，将无法再访问该字段，但是可以正常访问其它的字段\n",
    "\n",
    "let user1 = User {\n",
    "    email: String::from(\"someone@example.com\"),\n",
    "    username: String::from(\"someusername123\"),\n",
    "    active: true,\n",
    "    sign_in_count: 1,\n",
    "};\n",
    "let user2 = User {\n",
    "    active: user1.active,\n",
    "    username: user1.username,\n",
    "    email: String::from(\"another@example.com\"),\n",
    "    sign_in_count: user1.sign_in_count,\n",
    "};\n",
    "println!(\"{}\", user1.active);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "borrow of partially moved value: `user1`",
     "output_type": "error",
     "traceback": [
      "    username: user1.username,",
      "\u001b[91m              ^^^^^^^^^^^^^^\u001b[0m \u001b[94mvalue partially moved here\u001b[0m",
      "println!(\"{:?}\", user1);",
      "\u001b[91m                 ^^^^^\u001b[0m \u001b[94mvalue borrowed here after partial move\u001b[0m",
      "borrow of partially moved value: `user1`"
     ]
    }
   ],
   "source": [
    "let user1 = User {\n",
    "    email: String::from(\"someone@example.com\"),\n",
    "    username: String::from(\"someusername123\"),\n",
    "    active: true,\n",
    "    sign_in_count: 1,\n",
    "};\n",
    "let user2 = User {\n",
    "    active: user1.active,\n",
    "    username: user1.username,\n",
    "    email: String::from(\"another@example.com\"),\n",
    "    sign_in_count: user1.sign_in_count,\n",
    "};\n",
    "\n",
    "// 下面这行会报错\n",
    "println!(\"{:?}\", user1);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 结构体的内存排列"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "File { name: \"f1.txt\", data: [] }\n",
      "f1.txt is 0 bytes long\n"
     ]
    }
   ],
   "source": [
    "#[derive(Debug)]\n",
    " struct File {\n",
    "   name: String,\n",
    "   data: Vec<u8>,\n",
    " }\n",
    "\n",
    " fn main() {\n",
    "   let f1 = File {\n",
    "     name: String::from(\"f1.txt\"),\n",
    "     data: Vec::new(),\n",
    "   };\n",
    "\n",
    "   let f1_name = &f1.name;\n",
    "   let f1_length = &f1.data.len();\n",
    "\n",
    "   println!(\"{:?}\", f1);\n",
    "   println!(\"{} is {} bytes long\", f1_name, f1_length);\n",
    " }\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![2.1](./images/2.1.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 元组结构体(Tuple Struct)\n",
    "\n",
    "结构体必须要有名称，但是结构体的字段可以没有名称，这种结构体长得很像元组，因此被称为元组结构体\n",
    "\n",
    "元组结构体在你希望有一个整体名称，但是又不关心里面字段的名称时将非常有用。例如下面的 `Point` 元组结构体，众所周知 3D 点是 `(x, y, z)` 形式的坐标点，因此我们无需再为内部的字段逐一命名为：`x`, `y`, `z`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Color(i32, i32, i32);\n",
    "struct Point(i32, i32, i32);\n",
    "\n",
    "let black = Color(0, 0, 0);\n",
    "let origin = Point(0, 0, 0);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 单元结构体(Unit-like Struct)\n",
    "\n",
    "还记得之前讲过的基本没啥用的[单元类型](https://course.rs/basic/base-type/char-bool.html#单元类型)吧？单元结构体就跟它很像，没有任何字段和属性，但是好在，它还挺有用。\n",
    "\n",
    "如果你定义一个类型，但是不关心该类型的内容，只关心它的行为时，就可以使用 `单元结构体`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct AlwaysEqual;\n",
    "\n",
    "let subject = AlwaysEqual;\n",
    "\n",
    "// 我们不关心 AlwaysEqual 的字段数据，只关心它的行为，因此将它声明为单元结构体，然后再为它实现某个特征\n",
    "impl SomeTrait for AlwaysEqual {\n",
    "\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 结构体数据的所有权\n",
    "\n",
    "结构体倾向于持有自身数据的所有权（如使用 `String`），以避免涉及引用时必须引入并正确管理生命周期。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "missing lifetime specifier",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0106] Error:\u001b[0m missing lifetime specifier",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_2:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m,\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m               \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m               \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected named lifetime parameter",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "missing lifetime specifier",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0106] Error:\u001b[0m missing lifetime specifier",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_2:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m,\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected named lifetime parameter",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "struct User {\n",
    "    username: &str,\n",
    "    email: &str,\n",
    "    sign_in_count: u64,\n",
    "    active: bool,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let user1 = User {\n",
    "        email: \"someone@example.com\",\n",
    "        username: \"someusername123\",\n",
    "        active: true,\n",
    "        sign_in_count: 1,\n",
    "    };\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "未来在[生命周期(lifetimes)](https://course.rs/basic/lifetime.html)中会讲到如何修复这个问题以便在结构体中存储引用，不过在那之前，我们会避免在结构体中使用引用类型。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用 `#[derive(Debug)]` 来打印结构体的信息\n",
    "\n",
    "结构体不会自动实现 `Display` 或 `Debug`。\n",
    "\n",
    "- 使用 `{}` 需要实现 `Display`，编译器会报错：`Rectangle doesn't implement std::fmt::Display`。\n",
    "- 使用 `{:?}` 需要实现 `Debug`，同样会报错"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "`Rectangle` doesn't implement `std::fmt::Display`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m `Rectangle` doesn't implement `std::fmt::Display`",
      "    \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_3:1:1 \u001b[38;5;246m]\u001b[0m",
      "    \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m12 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m{\u001b[0m\u001b[38;5;100m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m1\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m                        \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m   \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m                         \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m required by this formatting parameter",
      " \u001b[38;5;240m   │\u001b[0m                               \u001b[38;5;54m│\u001b[0m    ",
      " \u001b[38;5;240m   │\u001b[0m                               \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `Rectangle` cannot be formatted with the default formatter",
      "\u001b[38;5;246m────╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "struct Rectangle {\n",
    "    width: u32,\n",
    "    height: u32,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let rect1 = Rectangle {\n",
    "        width: 30,\n",
    "        height: 50,\n",
    "    };\n",
    "\n",
    "    println!(\"rect1 is {}\", rect1);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**派生 Debug**\n",
    "- 派生 Debug的限制[附录 D](https://course.rs/appendix/derive.html)\n",
    "- https://course.rs/basic/formatted-output.html#debug-%E7%89%B9%E5%BE%81\n",
    "- [格式化输出](https://course.rs/basic/formatted-output.html#debug-%E7%89%B9%E5%BE%81)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 只要结构体所有字段本身都实现了 Debug（否则需要手动实现）, 可以用在所有的自定义结构体类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "rect1 is Rectangle { width: 30, height: 50 }\n",
      "rect1 is Rectangle {\n",
      "    width: 30,\n",
      "    height: 50,\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "// 派生 Debug\n",
    "\n",
    "#[derive(Debug)]\n",
    "struct Rectangle {\n",
    "    width: u32,\n",
    "    height: u32,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let rect1 = Rectangle { width: 30, height: 50 };\n",
    "    println!(\"rect1 is {:?}\", rect1);        // 常规调试输出\n",
    "    println!(\"rect1 is {:#?}\", rect1);      // 更易读的多行格式\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**手动实现**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Rectangle: 30×50\n",
      "rect1 = Rectangle: 30×50\n"
     ]
    }
   ],
   "source": [
    "// 手动实现 Display\n",
    "\n",
    "use std::fmt;\n",
    "\n",
    "struct Rectangle {\n",
    "    width: u32,\n",
    "    height: u32,\n",
    "}\n",
    "\n",
    "// 手动实现 Display\n",
    "impl fmt::Display for Rectangle {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n",
    "        // 自定义输出格式\n",
    "        write!(f, \"Rectangle: {}×{}\", self.width, self.height)\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let rect1 = Rectangle { width: 30, height: 50 };\n",
    "    println!(\"{}\", rect1);                // Rectangle: 30×50\n",
    "    println!(\"rect1 = {}\", rect1);        // rect1 = Rectangle: 30×50\n",
    "\n",
    "    // 如果还想用 {:?}，记得同时实现 Debug（见下）\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Rectangle { width: 30, height: 50 }\n",
      "Rectangle {\n",
      "    width: 30,\n",
      "    height: 50,\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "// 手动实现 Debug\n",
    "\n",
    "use std::fmt;\n",
    "\n",
    "struct Rectangle {\n",
    "    width: u32,\n",
    "    height: u32,\n",
    "}\n",
    "\n",
    "// 手动实现 Debug\n",
    "impl fmt::Debug for Rectangle {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n",
    "        // 可以自由决定输出形式\n",
    "        f.debug_struct(\"Rectangle\")\n",
    "            .field(\"width\", &self.width)\n",
    "            .field(\"height\", &self.height)\n",
    "            .finish()\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let rect1 = Rectangle { width: 30, height: 50 };\n",
    "    println!(\"{:?}\", rect1);   // Rectangle { width: 30, height: 50 }\n",
    "    println!(\"{:#?}\", rect1);  // Pretty-print 版本\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[**调试宏 `dbg!`**](https://doc.rust-lang.org/std/macro.dbg.html)\n",
    "- 自动打印文件名、行号和表达式值，输出到 `stderr`。\n",
    "- 使用时会暂时取得表达式所有权，然后返回结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[src/lib.rs:11:16] 30 * scale = 60\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[src/lib.rs:15:5] &rect1 = Rectangle {\n",
      "    width: 60,\n",
      "    height: 50,\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "#[derive(Debug)]\n",
    "struct Rectangle {\n",
    "    width: u32,\n",
    "    height: u32,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let scale = 2;\n",
    "    let rect1 = Rectangle {\n",
    "        width: dbg!(30 * scale),\n",
    "        height: 50,\n",
    "    };\n",
    "\n",
    "    dbg!(&rect1);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 枚举\n",
    "\n",
    "- https://course.rs/basic/compound-type/enum.html\n",
    "- https://practice-zh.course.rs/compound-types/enum.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/compound-types/enum.md\n",
    "\n",
    "枚举通过列举所有可能的成员来定义一种类型，使得像扑克牌花色这类互斥且穷尽的分类统一成同一概念。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enum PokerSuit {\n",
    "  Clubs,\n",
    "  Spades,\n",
    "  Diamonds,\n",
    "  Hearts,\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 枚举值\n",
    "\n",
    "枚举值是枚举类型的具体成员实例，它们既能代表简单常量又可携带任意多样的数据，使得同一类型下的不同变体共享统一接口并保持代码简洁高内聚。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let heart = PokerSuit::Hearts;\n",
    "let diamond = PokerSuit::Diamonds;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 目前来说，枚举值还不能带有值\n",
    "\n",
    "enum PokerSuit {\n",
    "    Clubs,\n",
    "    Spades,\n",
    "    Diamonds,\n",
    "    Hearts,\n",
    "}\n",
    "\n",
    "struct PokerCard {\n",
    "    suit: PokerSuit,\n",
    "    value: u8\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "   let c1 = PokerCard {\n",
    "       suit: PokerSuit::Clubs,\n",
    "       value: 1,\n",
    "   };\n",
    "   let c2 = PokerCard {\n",
    "       suit: PokerSuit::Diamonds,\n",
    "       value: 12,\n",
    "   };\n",
    "}\n",
    "\n",
    "main()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 更简的实现方式\n",
    "\n",
    "enum PokerCard {\n",
    "    Clubs(u8), // 直接将数据信息关联到枚举成员上\n",
    "    Spades(u8),\n",
    "    Diamonds(u8),\n",
    "    Hearts(u8),\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "   let c1 = PokerCard::Spades(5);\n",
    "   let c2 = PokerCard::Diamonds(13);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enum PokerCard { // 同一个枚举类型下的不同成员还能持有不同的数据类型\n",
    "    Clubs(u8),\n",
    "    Spades(u8),\n",
    "    Diamonds(char),\n",
    "    Hearts(char),\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "   let c1 = PokerCard::Spades(5);\n",
    "   let c2 = PokerCard::Diamonds('A');\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 来看一个来自标准库中的例子\n",
    "\n",
    "struct Ipv4Addr {\n",
    "    // --snip--\n",
    "}\n",
    "\n",
    "struct Ipv6Addr {\n",
    "    // --snip--\n",
    "}\n",
    "\n",
    "enum IpAddr {\n",
    "    V4(Ipv4Addr), // 任何类型的数据都可以放入枚举成员中：例如字符串、数值、结构体甚至另一个枚举\n",
    "    V6(Ipv6Addr),\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enum Message {\n",
    "    Quit, // 没有任何关联数据\n",
    "    Move { x: i32, y: i32 }, // 包含一个匿名结构体\n",
    "    Write(String), // 包含一个 String 字符串\n",
    "    ChangeColor(i32, i32, i32), // ChangeColor 包含三个 i32\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let m1 = Message::Quit;\n",
    "    let m2 = Message::Move{x:1,y:1};\n",
    "    let m3 = Message::ChangeColor(255,255,0);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 用结构体的方式来定义这些消息\n",
    "\n",
    "struct QuitMessage; // 单元结构体\n",
    "struct MoveMessage {\n",
    "    x: i32,\n",
    "    y: i32,\n",
    "}\n",
    "struct WriteMessage(String); // 元组结构体\n",
    "struct ChangeColorMessage(i32, i32, i32); // 元组结构体"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "由于每个结构体都有自己的类型，因此我们无法在需要同一类型的地方进行使用，例如某个函数它的功能是接受消息并进行发送，那么用枚举的方式，就可以接收不同的消息，但是用结构体，该函数无法接受 4 个不同的结构体作为参数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 同一化类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn new (stream: TcpStream) {\n",
    "  let mut s = stream;\n",
    "  if tls {\n",
    "    s = negotiate_tls(stream)\n",
    "  }\n",
    "\n",
    "  // websocket是一个 WebSocket<TcpStream> 或者 WebSocket<native_tls::TlsStream<TcpStream>> 类型\n",
    "  websocket = WebSocket::from_raw_socket(\n",
    "    s, ......)\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 通过枚举将不同底层连接类型统一包装成同一种 Websocket 变体，就能用一套逻辑处理无论是 TCP 还是 TLS 的长连接。\n",
    "\n",
    "enum Websocket {\n",
    "  Tcp(Websocket<TcpStream>),\n",
    "  Tls(Websocket<native_tls::TlsStream<TcpStream>>),\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "重点提示（面向 C++ 开发者）\n",
    "\n",
    "- **模式匹配**：`match` 是 Rust 的核心特性，比 `switch` 更强大，支持结构拆解和编译期穷举检查。\n",
    "- **所有权 / 借用**：无需显式 `delete`，所有权会跟随变量移动；函数结束后资源自动释放。\n",
    "- **trait 类似接口**：通过 `impl Trait for Type` 定义行为，与 C++ 的抽象基类不同，Rust 没有虚函数开销。\n",
    "- **错误处理**：`Result<T, E>` 与 `?` 运算符结合，使错误传播简洁。\n",
    "- **枚举 + 数据**：枚举成员可以携带任意类型的数据（比 C++ enum 强大），类似 `std::variant` 的超集。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Listening on 127.0.0.1:4000\n",
      "Incoming connection: Tls(FakeTlsStream(TcpStream { addr: 127.0.0.1:4000, peer: 127.0.0.1:34196, fd: 4 }))\n",
      "Received: hello\n",
      "\n",
      "Incoming connection: Tcp(TcpStream { addr: 127.0.0.1:4000, peer: 127.0.0.1:34500, fd: 4 })\n",
      "Received: world\n",
      "\n"
     ]
    }
   ],
   "source": [
    "use std::io::{Read, Result};\n",
    "use std::net::{TcpListener, TcpStream};\n",
    "\n",
    "/// 模拟 TLS 流（在真实项目中通常来自 `native_tls`、`rustls` 等库）\n",
    "///\n",
    "/// - Rust 中可以很容易地为泛型类型手动实现功能；这里我们只需要一个包装器来表现“TLS 层”。\n",
    "/// - `FakeTlsStream<T>` 持有一个底层流 `T`，用于展示“枚举成员关联不同类型”的能力。\n",
    "#[derive(Debug)]\n",
    "struct FakeTlsStream<T>(T);\n",
    "\n",
    "/// 为 FakeTlsStream 实现 `Read` trait，使其行为与底层流一致。\n",
    "///\n",
    "/// Rust 重度依赖 trait 来抽象接口；类似 C++ 的纯虚基类。\n",
    "/// 这里 `impl<T: Read> Read for FakeTlsStream<T>` 表示：\n",
    "/**\n",
    " *  - 对于任何实现了 `Read` 的类型 `T`，`FakeTlsStream<T>` 也实现 `Read`。\n",
    " *  - 因此枚举在匹配其变体时，可以统一调用 `read`。\n",
    " */\n",
    "impl<T: Read> Read for FakeTlsStream<T> {\n",
    "    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {\n",
    "        // 直接把调用委托给被包装的底层流。\n",
    "        // 真实的 TLS 实现会在这里进行解密等操作。\n",
    "        self.0.read(buf)\n",
    "    }\n",
    "}\n",
    "\n",
    "/// 枚举封装不同底层连接：TCP 和 TLS。\n",
    "///\n",
    "/// 与 C++ 中使用 `std::variant` 的思路相同，但 Rust 的枚举（`enum`）原生支持模式匹配，\n",
    "/**\n",
    " *   并且每个变体可以携带不同类型的数据。\n",
    " *\n",
    " * 这里：`Websocket::Tcp` 持有 `TcpStream`，`Websocket::Tls` 持有 `FakeTlsStream<TcpStream>`。\n",
    " */\n",
    "#[derive(Debug)]\n",
    "enum Websocket {\n",
    "    Tcp(TcpStream),\n",
    "    Tls(FakeTlsStream<TcpStream>),\n",
    "}\n",
    "\n",
    "impl Websocket {\n",
    "    /// 示例方法：统一读取一行数据。\n",
    "    ///\n",
    "    /// - `&mut self`：在 Rust 中，方法的第一个参数类似 `self`，但你要显式声明借用方式（可变 / 不可变）。\n",
    "    /// - 通过 `match` 对枚举进行模式匹配，分别处理 TCP/TLS 两种情况，但整体逻辑统一。\n",
    "    fn read_line(&mut self) -> Result<String> {\n",
    "        let mut buf = [0_u8; 64]; // 定长缓冲区，演示用途\n",
    "        let n = match self {\n",
    "            // `match` 类似 C++17 的 `std::visit`，但更强大且语法简洁。\n",
    "            Websocket::Tcp(stream) => stream.read(&mut buf)?,\n",
    "            Websocket::Tls(stream) => stream.read(&mut buf)?,\n",
    "        };\n",
    "        Ok(String::from_utf8_lossy(&buf[..n]).to_string())\n",
    "    }\n",
    "}\n",
    "\n",
    "/// 接受原始连接并根据条件包装成统一的枚举类型。\n",
    "///\n",
    "/// - 参数 `stream` 的所有权被移动进函数，这是 Rust 的所有权模型：函数结束前它一直归我们所有。\n",
    "/// - 返回的 `Websocket` 枚举同样拥有底层流的所有权（无需手动 `new` / `delete`）。\n",
    "fn accept_connection(stream: TcpStream, use_tls: bool) -> Websocket {\n",
    "    if use_tls {\n",
    "        let tls_stream = FakeTlsStream(stream);\n",
    "        Websocket::Tls(tls_stream)\n",
    "    } else {\n",
    "        Websocket::Tcp(stream)\n",
    "    }\n",
    "}\n",
    "\n",
    "/// 使用统一逻辑处理任意类型的 WebSocket 连接。\n",
    "///\n",
    "/// - 函数参数 `ws` 接受一个枚举值，调用端无需关注它具体是哪种流。\n",
    "/// - Rust 会在编译期验证所有匹配情况是否覆盖全面，避免遗漏。\n",
    "fn handle_websocket(mut ws: Websocket) -> Result<()> {\n",
    "    println!(\"Incoming connection: {ws:?}\");\n",
    "    let line = ws.read_line()?;\n",
    "    println!(\"Received: {line}\");\n",
    "    Ok(())\n",
    "}\n",
    "\n",
    "/// 程序入口：监听本地 TCP 端口并模拟处理 TCP/TLS 两种连接。\n",
    "///\n",
    "/// - `?` 运算符：若 `Result` 是 `Err`，直接向上传播错误，类似 C++ 中手动检查并返回。\n",
    "/// - `listener.incoming()` 返回迭代器，每个元素都是一个 `Result<TcpStream>`。\n",
    "fn main() -> Result<()> {\n",
    "    // 绑定监听地址；如果失败（例如端口被占用），错误会通过 `?` 返回。\n",
    "    let listener = TcpListener::bind(\"127.0.0.1:4000\")?;\n",
    "    println!(\"Listening on 127.0.0.1:4000\");\n",
    "\n",
    "    // 枚举所有进入的连接；`enumerate` 为每个连接附带一个递增编号。\n",
    "    for (idx, stream) in listener.incoming().enumerate() {\n",
    "        let stream = stream?; // 处理 `Result`，失败时早返回。\n",
    "        let use_tls = idx % 2 == 0; // 简单地模拟：偶数序号的连接走 “TLS” 分支。\n",
    "        let ws = accept_connection(stream, use_tls);\n",
    "        handle_websocket(ws)?;\n",
    "    }\n",
    "    Ok(())\n",
    "}\n",
    "\n",
    "main() ;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Option 枚举用于处理空值\n",
    "\n",
    "- https://course.rs/basic/compound-type/enum.html\n",
    "- https://practice-zh.course.rs/compound-types/enum.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/compound-types/enum.md\n",
    "\n",
    "[Option](https://doc.rust-lang.org/std/option/enum.Option.html) 枚举通过显式区分 `Some(T)` 与 `None`，把“有值”和“无值”的情形纳入类型系统，让你在编译期就必须处理潜在的空值，从而避免传统 `null` 带来的运行时崩溃。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> Option 的提出旨在从类型系统层面替代 C++ 中依赖裸指针或可空指针表达“可能没有值”的惯例，彻底解决由于 `nullptr` / 未检查可空值而导致的运行时崩溃和未定义行为问题。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enum Option<T> {\n",
    "    Some(T), // 表示含有值: 其中 T 是泛型参数，Some(T)表示该枚举成员的数据类型是 T，换句话说，Some 可以包含任何类型的数据\n",
    "    None,    // 表示没有值\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "let some_number = Some(5);\n",
    "let some_string = Some(\"a string\");\n",
    "\n",
    "let absent_number: Option<i32> = None;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot add `Option<i8>` to `i8`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m cannot add `Option<i8>` to `i8`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_3:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m+\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m no implementation for `i8 + Option<i8>`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let x: i8 = 5;\n",
    "let y: Option<i8> = Some(5);\n",
    "\n",
    "let sum = x + y; // Option<T> 和 T（这里 T 可以是任何类型）是不同的类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sum: 10\n"
     ]
    }
   ],
   "source": [
    "let x: i8 = 5;\n",
    "let y: Option<i8> = Some(5);\n",
    "\n",
    "let sum = match y {\n",
    "    Some(value) => x + value,\n",
    "    None => x, // 或者做其他处理\n",
    "};\n",
    "\n",
    "println!(\"Sum: {sum}\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "因为 `Option<T>` 与普通 `T` 类型严格区分，Rust 会强制你在使用可能为空的值之前显式匹配 `Some` 或 `None`，从而在编译期阻止空值误用。\n",
    "- Rust 把“可能缺席”的值包装进 `Option<T>`，与原始类型彻底区分。\n",
    "- 只有显式构造 `Some(...)` / `None` 才能得到 `Option<T>`；否则，值就被保证为非空。\n",
    "- 在使用 `Option<T>` 时必须匹配 `Some`/`None` 或调用相应的拆箱方法，编译器会强制你覆盖空值场景。\n",
    "- 因此，任何不是 `Option<T>` 的值都可以安全地视为“必定存在”。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "five: Some(5)\n",
      "six: Some(6)\n",
      "none: None\n"
     ]
    }
   ],
   "source": [
    "fn plus_one(x: Option<i32>) -> Option<i32> {\n",
    "    match x { // plus_one 通过 match 来处理不同 Option 的情况\n",
    "        None => None,\n",
    "        Some(i) => Some(i + 1),\n",
    "    }\n",
    "}\n",
    "\n",
    "let five = Some(5);\n",
    "let six = plus_one(five);\n",
    "let none = plus_one(None);\n",
    "\n",
    "\n",
    "println!(\"five: {:?}\", five);\n",
    "println!(\"six: {:?}\", six);\n",
    "println!(\"none: {:?}\", none);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数组\n",
    "\n",
    "- https://course.rs/basic/compound-type/array.html\n",
    "- https://practice-zh.course.rs/compound-types/array.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/compound-types/array.md\n",
    "\n",
    "Rust 中的数组（array）是固定长度、元素同型且线性排列的基本集合类型，而可变长度需求则由动态数组 [`Vec<T>`](https://course.rs/basic/collections/vector.html)（类似于 `String` 对应 `&str` 的关系）承担。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let a = [1, 2, 3, 4, 5]; // 数组 array 是存储在栈上; 动态数组 Vector 是存储在堆上"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let months = [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\",\n",
    "              \"August\", \"September\", \"October\", \"November\", \"December\"];"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 为数组声明类型\n",
    "\n",
    "let a: [i32; 5] = [1, 2, 3, 4, 5]; // 数组的元素类型要统一，长度要固定"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 初始化一个某个值重复出现 N 次的数组\n",
    "\n",
    "let a = [3; 5]; // [3; 5] 和 [类型; 长度]: a 数组包含 5 个元素，这些元素的初始化值为 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 访问数组元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let a = [9, 8, 7, 6, 5];\n",
    "\n",
    "    let first = a[0]; // 获取a数组第一个元素, 数组的索引下标是从 0 开始的\n",
    "    let second = a[1]; // 获取第二个元素\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**越界访问**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "this operation will panic at runtime",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[unconditional_panic] Error:\u001b[0m this operation will panic at runtime",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_13:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54m[\u001b[0m\u001b[38;5;54m5\u001b[0m\u001b[38;5;54m]\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                     \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m index out of bounds: the length is 5 but the index is 5",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let a = [9, 8, 7, 6, 5];\n",
    "println!(\"a: {:?}\", a);\n",
    "\n",
    "let out_of_bounds = a[5];\n",
    "println!(\"out_of_bounds: {:?}\", out_of_bounds);\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! cd variable/out_of_bounds && cargo run\n",
    "\n",
    "Please enter an array index.\n",
    "5\n",
    "\n",
    "thread 'main' panicked at src/main.rs:19:19:\n",
    "index out of bounds: the len is 5 but the index is 5\n",
    "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**数组元素为非基础类型**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "the trait bound `String: Copy` is not satisfied",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m the trait bound `String: Copy` is not satisfied",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_14:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m[\u001b[0m\u001b[38;5;54mS\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;54mf\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m\"\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54m!\u001b[0m\u001b[38;5;54m\"\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m8\u001b[0m\u001b[38;5;249m]\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m              \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                            \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m the trait `Copy` is not implemented for `String`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let array = [String::from(\"rust is good!\"); 8]; // 基本类型在 Rust 中赋值是以 Copy 的形式, let array=[3;5]底层就是不断的Copy出来的\n",
    "\n",
    "println!(\"{:#?}\", array);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[\n",
      "    \"rust is good!\",\n",
      "    \"rust is good!\",\n",
      "    \"rust is good!\",\n",
      "]\n"
     ]
    }
   ],
   "source": [
    "let array = [String::from(\"rust is good!\"),String::from(\"rust is good!\"),String::from(\"rust is good!\")];\n",
    "\n",
    "println!(\"{:#?}\", array);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[\n",
      "    \"rust is good!\",\n",
      "    \"rust is good!\",\n",
      "    \"rust is good!\",\n",
      "    \"rust is good!\",\n",
      "    \"rust is good!\",\n",
      "    \"rust is good!\",\n",
      "    \"rust is good!\",\n",
      "    \"rust is good!\",\n",
      "]\n"
     ]
    }
   ],
   "source": [
    "let array: [String; 8] = std::array::from_fn(|_i| String::from(\"rust is good!\"));\n",
    "println!(\"{:#?}\", array);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "闭包: `|_i| String::from(\"rust is good!\")`：\n",
    "- 参数 `_i` 是当前元素的索引，开头的下划线表示这个变量未使用（避免编译器发出 “unused variable” 警告）。\n",
    "- 闭包每次都会新建并返回一个 `String`，内容为 `\"rust is good!\"`。因为 `String::from` 每次都会分配并复制那段文本，所以数组里的每个元素都是独立的 `String` 实例，而不是共享同一块数据"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 数组切片"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let a: [i32; 5] = [1, 2, 3, 4, 5]; // 类型是[i32;5]\n",
    "\n",
    "let slice: &[i32] = &a[1..3]; // 类型是&[i32]\n",
    "\n",
    "assert_eq!(slice, &[2, 3]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "切片的特点：\n",
    "\n",
    "- 切片的长度可以与数组不同，并不是固定的，而是取决于你使用时指定的起始和结束位置\n",
    "- 创建切片的代价非常小，因为切片只是针对底层数组的一个引用\n",
    "- 切片类型 `[T] `拥有不固定的大小，而切片引用类型 `&[T]` 则具有固定的大小，因为 Rust 很多时候都需要固定大小数据类型，因此 `&[T] `更有用，`&str` 字符串切片也同理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 总结\n",
    "\n",
    "- **数组类型容易跟数组切片混淆**，`[T;n]` 描述了一个数组的类型，而 `[T]` 描述了切片的类型， 因为切片是运行期的数据结构，它的长度无法在编译期得知，因此不能用 `[T;n]` 的形式去描述\n",
    "- `[u8; 3]`和`[u8; 4]`是不同的类型，数组的长度也是类型的一部分\n",
    "- **在实际开发中，使用最多的是数组切片`[T]`**，我们往往通过引用的方式去使用`&[T]`，因为后者有固定的类型大小"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3]: \t1 + 10 = 11\t2 + 10 = 12\t3 + 10 = 13\t([1, 2, 3] = 6)\n",
      "[1, 2, 3]: \t1 + 10 = 11\t2 + 10 = 12\t3 + 10 = 13\t([1, 2, 3] = 6)\n",
      "[0, 0, 0]: \t0 + 10 = 10\t0 + 10 = 10\t0 + 10 = 10\t([0, 0, 0] = 0)\n",
      "[0, 0, 0]: \t0 + 10 = 10\t0 + 10 = 10\t0 + 10 = 10\t([0, 0, 0] = 0)\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "  // 编译器自动推导出one的类型\n",
    "  let one             = [1, 2, 3];\n",
    "  // 显式类型标注\n",
    "  let two: [u8; 3]    = [1, 2, 3];\n",
    "  let blank1          = [0; 3];\n",
    "  let blank2: [u8; 3] = [0; 3];\n",
    "\n",
    "  // arrays是一个二维数组，其中每一个元素都是一个数组，元素类型是[u8; 3]\n",
    "  let arrays: [[u8; 3]; 4]  = [one, two, blank1, blank2];\n",
    "\n",
    "  // 借用arrays的元素用作循环中\n",
    "  for a in &arrays {\n",
    "    print!(\"{:?}: \", a);\n",
    "    // 将a变成一个迭代器，用于循环\n",
    "    // 你也可以直接用for n in a {}来进行循环\n",
    "    for n in a.iter() {\n",
    "      print!(\"\\t{} + 10 = {}\", n, n+10);\n",
    "    }\n",
    "\n",
    "    let mut sum = 0;\n",
    "    // 0..a.len,是一个 Rust 的语法糖，其实就等于一个数组，元素是从0,1,2一直增加到到a.len-1\n",
    "    for i in 0..a.len() {\n",
    "      sum += a[i];\n",
    "    }\n",
    "    println!(\"\\t({:?} = {})\", a, sum);\n",
    "  }\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.5. 流程控制 / Flow control\n",
    "\n",
    "- https://course.rs/basic/flow-control.html\n",
    "- https://practice-zh.course.rs/flow-control.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/flow-control.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用 if 来做分支控制"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The value of number is: 5\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let condition = true;\n",
    "    let number = if condition { \n",
    "        5\n",
    "    } else {\n",
    "        6\n",
    "    };\n",
    "\n",
    "    println!(\"The value of number is: {}\", number);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 用 `if` 来赋值时，要保证每个分支返回的类型一样, [if表达式](https://course.rs/appendix/expressions.html#if%E8%A1%A8%E8%BE%BE%E5%BC%8F)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用 else if 来处理多重条件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "number is divisible by 3\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let n = 6;\n",
    "\n",
    "    if n % 4 == 0 {\n",
    "        println!(\"number is divisible by 4\");\n",
    "    } else if n % 3 == 0 {\n",
    "        println!(\"number is divisible by 3\");\n",
    "    } else if n % 2 == 0 {\n",
    "        println!(\"number is divisible by 2\");\n",
    "    } else {\n",
    "        println!(\"number is not divisible by 4, 3, or 2\");\n",
    "    }\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "就算有多个分支能匹配，也只有第一个匹配的分支会被执行！\n",
    "\n",
    "`match` 专门用以解决多分支模式匹配的问题。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 循环控制\n",
    "\n",
    "- https://course.rs/basic/flow-control.html\n",
    "- https://practice-zh.course.rs/flow-control.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/flow-control.md\n",
    "\n",
    "| 循环形式             | 典型语法                                                     | 核心特性                                                     | 所有权 / 借用                                                | 常见场景                                                   | 注意事项                                                     |\n",
    "| -------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ---------------------------------------------------------- | ------------------------------------------------------------ |\n",
    "| `for`                | `for item in collection { … }`<br>`for i in 0..n { … }`<br>`for (i, v) in collection.iter().enumerate() { … }` | 基于迭代器的高层循环；编译期即可验证索引合法性；支持 `_` 忽略变量；可配合 `.iter()` / `.iter_mut()` / `.into_iter()` 控制借用或转移所有权 | `for item in collection` → 转移所有权<br>`for item in &collection` → 不可变借用<br>`for item in &mut collection` → 可变借用 | 遍历集合元素；需要同时访问索引和值；需要高性能且安全的遍历 | 对未实现 `Copy` 的集合直接迭代会移动所有权；使用 `enumerate()` 获取索引；相比 `while` 更简洁、安全、无运行时边界检查 |\n",
    "| `while`              | `while condition { … }`                                      | 条件为真时持续执行；条件在每轮循环前检查                     | 通常配合可变状态变量；需手动管理索引或计数                   | 条件驱动的循环；需要在循环体内修改条件变量                 | 易出现索引越界或忘记更新条件导致死循环；存在运行时边界检查开销 |\n",
    "| `loop`               | `loop { … }`<br>`break value;`                               | 无条件无限循环；必须用 `break` 退出，可携带返回值；`loop` 本身是表达式 | 取决于循环体内对数据的操作；常与可变借用或所有权转移配合     | 需要手动控制退出时机的场景；实现重试、状态机、异步轮询等   | 必须确保某处 `break`（或 `return`、`panic`）以免无限占用 CPU；`break` 可返回值供外层绑定 |\n",
    "| `continue`（关键字） | `if condition { continue; }`                                 | 跳过当前迭代剩余部分，立刻进入下一轮                         | 不改变循环的所有权语义                                       | 过滤特定元素；跳过不需处理的情况                           | 注意不要忽略对循环状态的必要更新，避免死循环                 |\n",
    "| `break`（关键字）    | `if condition { break; }`<br>`break value;`                  | 立即终止当前循环；可返回值给 `for` / `while` / `loop` 外部   | 不改变循环的所有权语义                                       | 结束遍历、查找目标后退出、`loop` 返回值                    | 在 `loop` 中常用于返回计算结果；注意与 `match` 嵌套时需 `break 'label` 指定目标循环 |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### for 循环"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "// for 和 in 的联动，语义表达如下\n",
    "\n",
    "for 元素 in 集合 {\n",
    "  // 使用元素干一些你懂我不懂的事情\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    for i in 1..=5 {\n",
    "        println!(\"{}\", i);\n",
    "    }\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 如果不使用引用的话，所有权会被转移（move）到 for 语句块中，后面就无法再使用这个集合了)\n",
    "\n",
    "for item in &container {\n",
    "  // ...\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 如果想在循环中，修改该元素，可以使用 mut 关键字：\n",
    "\n",
    "for item in &mut collection {\n",
    "  // ...\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "第1个元素是4\n",
      "第2个元素是3\n",
      "第3个元素是2\n",
      "第4个元素是1\n"
     ]
    }
   ],
   "source": [
    "// 如果想在循环中获取元素的索引\n",
    "\n",
    "fn main() {\n",
    "    let a = [4, 3, 2, 1];\n",
    "    // `.iter()` 方法把 `a` 数组变成一个迭代器\n",
    "    for (i, v) in a.iter().enumerate() {\n",
    "        println!(\"第{}个元素是{}\", i + 1, v);\n",
    "    }\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 用 for 循环控制某个过程执行 10 次，但是又不想单独声明一个变量来控制这个流程\n",
    "\n",
    "for _ in 0..10 {\n",
    "  // ...\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**两种循环方式优劣对比**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 第一种: 循环索引，然后通过索引下标去访问集合\n",
    "let collection = [1, 2, 3, 4, 5];\n",
    "for i in 0..collection.len() {\n",
    "  let item = collection[i];\n",
    "  // ...\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 第二种: 直接循环集合中的元素\n",
    "for item in collection {\n",
    "\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**性能**：\n",
    "- 第一种使用方式中 `collection[index]` 的索引访问，会因为边界检查(Bounds Checking)导致运行时的性能损耗 —— Rust 会检查并确认 `index` 是否落在集合内，\n",
    "- 但是第二种直接迭代的方式就不会触发这种检查，因为编译器会在编译时就完成分析并证明这种访问是合法的\n",
    "\n",
    "**安全**：\n",
    "- 第一种方式里对 `collection` 的索引访问是非连续的，存在一定可能性在两次访问之间，`collection` 发生了变化，导致脏数据产生。\n",
    "- 而第二种直接迭代的方式是连续访问，因此不存在这种风险( 由于所有权限制，在访问过程中，数据并不会发生变化)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### continue"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "3\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "for i in 1..4 {\n",
    "    if i == 2 {\n",
    "        continue; // 使用 continue 可以跳过当前当次的循环，开始下次的循环\n",
    "    }\n",
    "    println!(\"{}\", i);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "for i in 1..4 {\n",
    "    if i == 2 {\n",
    "        break; // 使用 break 可以直接跳出当前整个循环\n",
    "    }\n",
    "    println!(\"{}\", i);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "counter stopped at 10, doubled value = 20\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let mut counter = 0;\n",
    "    let doubled_at_ten = loop {\n",
    "        counter += 1;\n",
    "\n",
    "        if counter == 10 {\n",
    "            break counter * 2; // break 可以单独使用，也可以带一个返回值，有些类似 return\n",
    "        }\n",
    "    };\n",
    "\n",
    "    println!(\"counter stopped at {counter}, doubled value = {doubled_at_ten}\");\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### while 循环"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let mut n = 0;\n",
    "\n",
    "    while n <= 5  { // 当该条件为 true 时，继续循环，条件为 false，跳出循环\n",
    "        println!(\"{}!\", n);\n",
    "\n",
    "        n = n + 1;\n",
    "    }\n",
    "\n",
    "    println!(\"我出来了！\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 用其它方式组合实现\n",
    "\n",
    "fn main() {\n",
    "    let mut n = 0;\n",
    "\n",
    "    loop {\n",
    "        if n > 5 {\n",
    "            break\n",
    "        }\n",
    "        println!(\"{}\", n);\n",
    "        n+=1;\n",
    "    }\n",
    "\n",
    "    println!(\"我出来了！\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**while vs for**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 用 while 来实现 for 的功能\n",
    "\n",
    "fn main() {\n",
    "    let a = [10, 20, 30, 40, 50];\n",
    "    let mut index = 0;\n",
    "\n",
    "    while index < 5 {\n",
    "        println!(\"the value is: {}\", a[index]);\n",
    "\n",
    "        index = index + 1;\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// for 并不会使用索引去访问数组，因此更安全也更简洁，同时避免 运行时的边界检查，性能更高。\n",
    "\n",
    "fn main() {\n",
    "    let a = [10, 20, 30, 40, 50];\n",
    "\n",
    "    for element in a.iter() {\n",
    "        println!(\"the value is: {}\", element);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### loop 循环"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    loop { // loop 就是一个简单的无限循环，你可以在内部实现逻辑通过 break 关键字来控制循环何时结束\n",
    "        println!(\"again!\");\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The result is 20\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let mut counter = 0;\n",
    "\n",
    "    let result = loop { // loop 是一个表达式，因此可以返回一个值\n",
    "        counter += 1;\n",
    "\n",
    "        if counter == 10 {\n",
    "            break counter * 2;\n",
    "        }\n",
    "    };\n",
    "\n",
    "    println!(\"The result is {}\", result);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.6. 模式匹配 / Pattern Match\n",
    "\n",
    "- https://course.rs/basic/match-pattern/match-if-let.html\n",
    "- https://practice-zh.course.rs/pattern-match/match-iflet.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/pattern-match/match.md\n",
    "\n",
    "模式匹配是 Rust 用来优雅解构复杂类型并取代繁琐多分支逻辑（如处理 `Option` 或多个条件）的核心工具。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## match 和 if let"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "South or North\n"
     ]
    }
   ],
   "source": [
    "enum Direction {\n",
    "    East,\n",
    "    West,\n",
    "    North,\n",
    "    South,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let dire = Direction::South;\n",
    "    match dire {\n",
    "        Direction::East => println!(\"East\"),\n",
    "        Direction::North | Direction::South => {\n",
    "            println!(\"South or North\");\n",
    "        },\n",
    "        _ => println!(\"West\"),\n",
    "    };\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里我们想去匹配 `dire` 对应的枚举类型，因此在 `match` 中用三个匹配分支来完全覆盖枚举变量 `Direction` 的所有成员类型，有以下几点值得注意：\n",
    "\n",
    "- `match` 的匹配必须要穷举出所有可能，因此这里用 `_` 来代表未列出的所有可能性\n",
    "- `match` 的每一个分支都必须是一个表达式，且所有分支的表达式最终返回值的类型必须相同\n",
    "- **X | Y**，类似逻辑运算符 `或`，代表该分支可以匹配 `X` 也可以匹配 `Y`，只要满足一个即可\n",
    "\n",
    "其实 `match` 跟其他语言中的 `switch` 非常像，`_` 类似于 `switch` 中的 `default`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### match 匹配"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将模式与 target 进行匹配，即为**模式匹配**"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "// match 的通用形式\n",
    "\n",
    "match target {\n",
    "    模式1 => 表达式1,\n",
    "    模式2 => {\n",
    "        语句1;\n",
    "        语句2;\n",
    "        表达式2\n",
    "    },\n",
    "    _ => 表达式3\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enum Coin {\n",
    "    Penny,\n",
    "    Nickel,\n",
    "    Dime,\n",
    "    Quarter,\n",
    "}\n",
    "\n",
    "fn value_in_cents(coin: Coin) -> u8 {\n",
    "    match coin { // if 后的表达式必须是一个布尔值，而 match 后的表达式返回值可以是任意类型\n",
    "        Coin::Penny =>  { // => 运算符将模式和将要运行的代码分开\n",
    "            println!(\"Lucky penny!\");\n",
    "            1\n",
    "        },\n",
    "        Coin::Nickel => 5,\n",
    "        Coin::Dime => 10,\n",
    "        Coin::Quarter => 25,\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**使用 match 表达式赋值**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "::1\n"
     ]
    }
   ],
   "source": [
    "enum IpAddr {\n",
    "   Ipv4,\n",
    "   Ipv6\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let ip1 = IpAddr::Ipv6;\n",
    "    let ip_str = match ip1 {\n",
    "        IpAddr::Ipv4 => \"127.0.0.1\",\n",
    "        _ => \"::1\",\n",
    "    };\n",
    "\n",
    "    println!(\"{}\", ip_str);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**模式绑定**\n",
    "- 模式匹配的另外一个重要功能是从模式中取出绑定的值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#[derive(Debug)]\n",
    "enum UsState {\n",
    "    Alabama,\n",
    "    Alaska,\n",
    "    // --snip--\n",
    "}\n",
    "\n",
    "enum Coin {\n",
    "    Penny,\n",
    "    Nickel,\n",
    "    Dime,\n",
    "    Quarter(UsState), // 25美分硬币\n",
    "}\n",
    "\n",
    "// 获取到 25 美分硬币上刻印的州的名称\n",
    "fn value_in_cents(coin: Coin) -> u8 {\n",
    "    match coin {\n",
    "        Coin::Penny => 1,\n",
    "        Coin::Nickel => 5,\n",
    "        Coin::Dime => 10,\n",
    "        Coin::Quarter(state) => { // 在匹配 Coin::Quarter(state) 模式时，我们把它内部存储的值绑定到了 state 变量上，因此 state 变量就是对应的 UsState 枚举类型\n",
    "            println!(\"State quarter from {:?}!\", state);\n",
    "            25\n",
    "        },\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello Rust\n",
      "point from (0, 0) move to (1, 2)\n",
      "change color into '(r:255, g:255, b:0)', 'b' has been ignored\n"
     ]
    }
   ],
   "source": [
    "// 定义一个枚举（enum）`Action`，用于描述不同的动作类型。\n",
    "// 每个枚举变体可以携带不同种类的数据：\n",
    "// - `Say(String)`：包含一段要输出的文本。\n",
    "// - `MoveTo(i32, i32)`：包含目标坐标 (x, y)。\n",
    "// - `ChangeColorRGB(u16, u16, u16)`：包含 RGB 三原色数值（例如 0-255）。\n",
    "enum Action {\n",
    "    Say(String),\n",
    "    MoveTo(i32, i32),\n",
    "    ChangeColorRGB(u16, u16, u16),\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    // 使用一个数组保存一系列需要执行的动作。\n",
    "    // 这里演示了如何构造各个枚举变体。\n",
    "    let actions = [\n",
    "        Action::Say(\"Hello Rust\".to_string()),\n",
    "        Action::MoveTo(1, 2),\n",
    "        Action::ChangeColorRGB(255, 255, 0),\n",
    "    ];\n",
    "\n",
    "    // 遍历数组中的每一个动作，并使用 `match` 进行模式匹配，\n",
    "    // 根据具体的枚举变体执行对应的逻辑。\n",
    "    for action in actions {\n",
    "        match action {\n",
    "            // 匹配到 `Action::Say` 变体时，将其中的字符串绑定到变量 `s`。\n",
    "            Action::Say(s) => {\n",
    "                println!(\"{}\", s);\n",
    "            }\n",
    "            // 匹配到 `Action::MoveTo` 变体时，将坐标分别绑定到 `x`、`y`。\n",
    "            Action::MoveTo(x, y) => {\n",
    "                println!(\"point from (0, 0) move to ({}, {})\", x, y);\n",
    "            }\n",
    "            // 匹配到 `Action::ChangeColorRGB` 变体时，将前三个参数绑定到 `r`、`g`、`_`。\n",
    "            // 使用 `_` 表示忽略第三个参数（蓝色通道），因此不会产生未使用变量的警告。\n",
    "            Action::ChangeColorRGB(r, g, _) => {\n",
    "                println!(\n",
    "                    \"change color into '(r:{}, g:{}, b:0)', 'b' has been ignored\",\n",
    "                    r, g,\n",
    "                );\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**穷尽匹配**\n",
    "- match 的匹配必须穷尽所有情况"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "non-exhaustive patterns: `Direction::West` not covered",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0004] Error:\u001b[0m non-exhaustive patterns: `Direction::West` not covered",
      "    \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_32:1:1 \u001b[38;5;246m]\u001b[0m",
      "    \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m10 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m           \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m             \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m pattern `Direction::West` not covered",
      " \u001b[38;5;240m   │\u001b[0m ",
      " \u001b[38;5;246m14 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m,\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m          \u001b[38;5;100m│\u001b[0m ",
      " \u001b[38;5;240m   │\u001b[0m          \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown: `,",
      "        Direction::West => todo!()`",
      "\u001b[38;5;246m────╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "enum Direction {\n",
    "    East,\n",
    "    West,\n",
    "    North,\n",
    "    South,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let dire = Direction::South;\n",
    "    match dire {\n",
    "        Direction::East => println!(\"East\"),\n",
    "        Direction::North | Direction::South => {\n",
    "            println!(\"South or North\");\n",
    "        },\n",
    "    };\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**_ 通配符**\n",
    "- 当我们不想在匹配时列出所有值的时候，可以使用 Rust 提供的一个特殊模式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let some_u8_value = 0u8; // u8 可以拥有 0 到 255 的有效的值\n",
    "match some_u8_value {\n",
    "    1 => println!(\"one\"),\n",
    "    3 => println!(\"three\"),\n",
    "    5 => println!(\"five\"),\n",
    "    7 => println!(\"seven\"),\n",
    "    _ => (), // 通过将 _ 其放置于其他分支后，_ 将会匹配所有遗漏的值。() 表示返回单元类型与所有分支返回值的类型相同，所以当匹配到 _ 后，什么也不会发生。\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "other direction: South\n"
     ]
    }
   ],
   "source": [
    "#[derive(Debug)]\n",
    "enum Direction {\n",
    "    East,\n",
    "    West,\n",
    "    North,\n",
    "    South,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let dire = Direction::South;\n",
    "    match dire {\n",
    "        Direction::East => println!(\"East\"),\n",
    "        other => println!(\"other direction: {:?}\", other), // 除了_通配符，用一个变量来承载其他情况也是可以的。\n",
    "    };\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在某些场景下，我们其实只关心某一个值是否存在，此时 `match` 就显得过于啰嗦"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### if let 匹配"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 有时会遇到只有一个模式的值需要被处理，其它值直接忽略的场景，如果用 match 来处理就要写成下面这样：\n",
    "\n",
    "let v = Some(3u8);\n",
    "match v { \n",
    "    Some(3) => println!(\"three\"),\n",
    "    _ => (),\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if let Some(3) = v { // 当你只要匹配一个条件，且忽略其他条件时就用 if let ，否则都用 match\n",
    "    println!(\"three\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### matches!宏\n",
    "\n",
    "`matches!`，它可以将一个表达式跟模式进行匹配，然后返回匹配的结果 `true` or `false`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enum MyEnum {\n",
    "    Foo,\n",
    "    Bar\n",
    "}\n",
    "\n",
    "let v = vec![MyEnum::Foo,MyEnum::Bar,MyEnum::Foo]; // 会创建一个 Vec<MyEnum>，其中元素顺序就是你传入的顺序; 凡是后面带 ! 的都是宏"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! cargo install cargo-expand"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "#![feature(prelude_import)]\n",
       "#[macro_use]\n",
       "extern crate std;\n",
       "#[prelude_import]\n",
       "use std::prelude::rust_2024::*;\n",
       "enum MyEnum {\n",
       "    Foo,\n",
       "    Bar,\n",
       "}\n",
       "fn main() {\n",
       "    let v = <[_]>::into_vec(\n",
       "        ::alloc::boxed::box_new([MyEnum::Foo, MyEnum::Bar, MyEnum::Foo]),\n",
       "    );\n",
       "}\n",
       "   Compiling num-traits v0.2.19\n",
       "    Checking num-integer v0.1.46\n",
       "    Checking num-complex v0.4.6\n",
       "    Checking num-bigint v0.4.6\n",
       "    Checking num-iter v0.1.45\n",
       "    Checking num-rational v0.4.2\n",
       "    Checking num v0.4.3\n",
       "    Checking expand v0.1.0 (/mnt/d/dev_learn/learnrustbyai_fk/rust_course/02_intro/expand)\n",
       "    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.48s\n",
       "\n"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd expand && cargo expand --bin expand"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#[derive(Debug, Clone, Copy)]\n",
    "enum MyEnum {\n",
    "    Foo,\n",
    "    Bar,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    // 手动创建 Vec，然后依次 push 元素\n",
    "    let mut v = Vec::new();\n",
    "    v.push(MyEnum::Foo);\n",
    "    v.push(MyEnum::Bar);\n",
    "    v.push(MyEnum::Foo);\n",
    "\n",
    "    println!(\"{:?}\", v);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let v = Vec::from([MyEnum::Foo, MyEnum::Bar, MyEnum::Foo]);\n",
    "    // 等价写法：let v = [MyEnum::Foo, MyEnum::Bar, MyEnum::Foo].to_vec();\n",
    "\n",
    "    println!(\"{:?}\", v);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "binary operation `==` cannot be applied to type `&&MyEnum`",
     "output_type": "error",
     "traceback": [
      "v.iter().filter(|x| x == MyEnum::Foo);",
      "\u001b[91m                    ^\u001b[0m \u001b[94m&&MyEnum\u001b[0m",
      "v.iter().filter(|x| x == MyEnum::Foo);",
      "\u001b[91m                         ^^^^^^^^^^^\u001b[0m \u001b[94mMyEnum\u001b[0m",
      "v.iter().filter(|x| x == MyEnum::Foo);",
      "\u001b[91m                      ^^\u001b[0m \u001b[94merror: binary operation `==` cannot be applied to type `&&MyEnum`\u001b[0m",
      "binary operation `==` cannot be applied to type `&&MyEnum`"
     ]
    }
   ],
   "source": [
    "// 如果想对 v 进行过滤，只保留类型是 MyEnum::Foo 的元素，你可能想这么写\n",
    "v.iter().filter(|x| x == MyEnum::Foo);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 使用 matches!\n",
    "\n",
    "v.iter().filter(|x| matches!(x, MyEnum::Foo));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let foo = 'f';\n",
    "assert!(matches!(foo, 'A'..='Z' | 'a'..='z'));\n",
    "\n",
    "let bar = Some(4);\n",
    "assert!(matches!(bar, Some(x) if x > 2));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 变量遮蔽\n",
    "\n",
    "无论是 `match` 还是 `if let`，这里都是一个新的代码块，而且这里的绑定相当于新变量，如果你使用同名变量，会发生变量遮蔽："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "在匹配前，age是Some(30)\n",
      "匹配出来的age是30\n",
      "在匹配后，age是Some(30)\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "   let age = Some(30);\n",
    "   println!(\"在匹配前，age是{:?}\",age);\n",
    "   if let Some(age) = age { // = 右边 Some(i32) 类型的 age 被左边 i32 类型的新 age 遮蔽了，该遮蔽一直持续到 if let 语句块的结束\n",
    "       println!(\"匹配出来的age是{}\",age);\n",
    "   }\n",
    "\n",
    "   println!(\"在匹配后，age是{:?}\",age);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "在匹配前，age是Some(30)\n",
      "匹配出来的age是30\n",
      "在匹配后，age是Some(30)\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "   let age = Some(30);\n",
    "   println!(\"在匹配前，age是{:?}\",age);\n",
    "   match age {\n",
    "       Some(age) =>  println!(\"匹配出来的age是{}\",age),\n",
    "       _ => ()\n",
    "   }\n",
    "   println!(\"在匹配后，age是{:?}\",age);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "在匹配前，age是Some(30)\n",
      "匹配出来的age是30\n",
      "在匹配后，age是Some(30)\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "   let age = Some(30);\n",
    "   println!(\"在匹配前，age是{:?}\", age);\n",
    "   match age {\n",
    "       Some(x) =>  println!(\"匹配出来的age是{}\", x), // 最好不要使用同名，避免难以理解\n",
    "       _ => ()\n",
    "   }\n",
    "   println!(\"在匹配后，age是{:?}\", age);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 解构 Option"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 匹配 Option<T>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 使用 Option<T>，是为了从 Some 中取出其内部的 T 值以及处理没有值的情况\n",
    "\n",
    "fn plus_one(x: Option<i32>) -> Option<i32> {\n",
    "    match x {\n",
    "        None => None, // 如果其中没有值，则函数返回 None 值\n",
    "        Some(i) => Some(i + 1), // 如果其中含有一个值，将其加一\n",
    "    }\n",
    "}\n",
    "\n",
    "let five = Some(5);\n",
    "let six = plus_one(five);\n",
    "let none = plus_one(None);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**传入参数 Some(5)**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "None => None, // 首先是匹配 None 分支，因为值 Some(5) 并不匹配模式 None，所以继续匹配下一个分支。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "Some(i) => Some(i + 1), // Some(5) 与 Some(i) 匹配吗？当然匹配！它们是相同的成员。i 绑定了 Some 中包含的值，因此 i 的值是 5。接着匹配分支的代码被执行，最后将 i 的值加一并返回一个含有值 6 的新 Some。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**传入参数 None**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "None => None, // 接着考虑下 plus_one 的第二个调用，这次传入的 x 是 None， 我们进入 match 并与第一个分支相比较。\n",
    "              // 匹配上了！接着程序继续执行该分支后的代码：返回表达式 None 的值，也就是返回一个 None，因为第一个分支就匹配到了，其他的分支将不再比较。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 模式适用场景\n",
    "\n",
    "- https://course.rs/basic/match-pattern/pattern-match.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 分类         | 项目                                | 说明                            | 示例/要点                                                    |\n",
    "| ------------ | ----------------------------------- | ------------------------------- | ------------------------------------------------------------ |\n",
    "| 模式组成元素 | 字面值                              | 直接匹配具体常量或字面量。      | `match x { 0 => …, 1 => …, _ => … }`                         |\n",
    "|              | 解构结构体/枚举/数组/元组           | 把复合类型拆成其成员来匹配。    | `let (x, y, z) = (1, 2, 3);`<br>`match point { Point { x, y: 0 } => … }` |\n",
    "|              | 变量绑定                            | 将匹配到的值绑定到新的变量名。  | `Some(value) => println!(\"{value}\")`                         |\n",
    "|              | 通配符 `_`                          | 忽略当前字段或剩余所有情况。    | `_ => println!(\"others\")`                                    |\n",
    "|              | 占位符（`..`, `_`, `_name @ …` 等） | 处理可变长度或“绑定+忽略”场景。 | `Foo { x, .. }`、`value @ 1..=5 => …`                        |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 使用场景            | 基本语法                                                 | 特点                                                         | 代码摘要                                                     |\n",
    "| ------------------- | -------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |\n",
    "| `match` 分支        | `match VALUE { PATTERN => EXPR, … }`                     | **穷尽式**；需覆盖所有可能值，可用 `_` 兜底。                | <pre><code>match age {<br>    Some(x) => println!(\"{x}\"),<br>    None => println!(\"none\"),<br>}</code></pre> |\n",
    "| `if let` 分支       | `if let PATTERN = VALUE { … }`                           | **可驳式**；匹配成功执行块，忽略其他情况。                   | <pre><code>if let Some(x) = age {<br>    println!(\"{x}\");<br>}</code></pre> |\n",
    "| `while let` 循环    | `while let PATTERN = VALUE { … }`                        | 持续匹配；常用于迭代直到返回 `None`。                        | <pre><code>while let Some(top) = stack.pop() {<br>    println!(\"{top}\");<br>}</code></pre> |\n",
    "| `for` 循环迭代      | `for PATTERN in ITER { … }`                              | 对迭代器产出的元素逐个匹配。                                 | <pre><code>for (index, value) in v.iter().enumerate() {<br>    println!(\"{value} at {index}\");<br>}</code></pre> |\n",
    "| `let` 绑定          | `let PATTERN = EXPR;`                                    | **必需完全匹配**；类型与结构需一致。                         | <pre><code>let (x, y, z) = (1, 2, 3);<br>// let (x, y) = (1, 2, 3); // E0308</code></pre> |\n",
    "| 函数参数            | `fn foo(PATTERN: Type) { … }`                            | 形参可直接写成模式。                                         | <pre><code>fn print_coordinates(&(x, y): &(i32, i32)) {<br>    println!(\"{x}, {y}\");<br>}</code></pre> |\n",
    "| `let` vs `if let`   | `let PATTERN = VALUE;`<br>`if let PATTERN = VALUE { … }` | `let` 需穷尽；`if let` 可忽略其他分支。                      | `let Some(x) = opt; // error`<br>`if let Some(x) = opt { … }` |\n",
    "| `let-else`（1.65+） | `let PATTERN = VALUE else { … };`                        | 让 `let` 成为可驳式；`else` 必须**发散**（`return`/`break`/`panic!` 等）。匹配成功的绑定在 `else` 之后仍可用。 | <pre><code>let Some(x) = opt else { return; };<br>println!(\"{x}\");</code></pre> |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### while let 条件循环"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Vec是动态数组\n",
    "let mut stack = Vec::new();\n",
    "\n",
    "// 向数组尾部插入元素\n",
    "stack.push(1);\n",
    "stack.push(2);\n",
    "stack.push(3);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "2\n",
      "1\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// stack.pop从数组尾部弹出元素\n",
    "while let Some(top) = stack.pop() { // 允许只要模式匹配就一直进行 while 循环\n",
    "    println!(\"{}\", top);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "2\n",
      "1\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// loop + if let\n",
    "loop {\n",
    "    if let Some(top) = stack.pop() {\n",
    "        println!(\"{}\", top);\n",
    "    } else {\n",
    "        break;\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "2\n",
      "1\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// loop + match\n",
    "loop {\n",
    "    match stack.pop() {\n",
    "        Some(top) => println!(\"{top}\"),\n",
    "        None => break,\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### for 循环"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a is at index 0\n",
      "b is at index 1\n",
      "c is at index 2\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "let v = vec!['a', 'b', 'c'];\n",
    "\n",
    "for (index, value) in v.iter().enumerate() { // 这里使用 enumerate 方法产生一个迭代器，该迭代器每次迭代会返回一个 (索引，值) 形式的元组，然后用 (index,value) 来匹配。\n",
    "    println!(\"{} is at index {}\", value, index);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### let 语句"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "let PATTERN = EXPRESSION;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "是的， 该语句我们已经用了无数次了，它也是一种模式匹配："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let x = 5; // x 也是一种模式绑定，代表将匹配的值绑定到变量 x 上. 在 Rust 中，变量名也是一种模式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let (x, y, z) = (1, 2, 3); // 将一个元组与模式进行匹配（模式和值的类型必需相同！），然后把 1, 2, 3 分别绑定到 x, y, z 上"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "mismatched types",
     "output_type": "error",
     "traceback": [
      "let (x, y) = (1, 2, 3); // 模式匹配要求两边的类型必须相同",
      "\u001b[91m    ^^^^^^\u001b[0m \u001b[94mexpected a tuple with 3 elements, found one with 2 elements\u001b[0m",
      "let (x, y) = (1, 2, 3); // 模式匹配要求两边的类型必须相同",
      "\u001b[91m             ^^^^^^^^^\u001b[0m \u001b[94mthis expression has type `({integer}, {integer}, {integer})`\u001b[0m",
      "mismatched types"
     ]
    }
   ],
   "source": [
    "let (x, y) = (1, 2, 3); // 模式匹配要求两边的类型必须相同, 对于元组来说，元素个数也是类型的一部分！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "函数参数也是模式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn foo(x: i32) { // 其中 x 就是一个模式\n",
    "    // 代码\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn print_coordinates(&(x, y): &(i32, i32)) { // 在参数中匹配元组\n",
    "    println!(\"Current location: ({}, {})\", x, y);\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let point = (3, 5);\n",
    "    print_coordinates(&point);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### let 和 if let"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let Some(x) = some_option_value; // 用来代表“某个 Option<T> 类型的值”"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "refutable pattern in local binding",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0005] Error:\u001b[0m refutable pattern in local binding",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_3:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mS\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54mx\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m        \u001b[38;5;100m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m        \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m pattern `None` not covered",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;100m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m help: you might want to use `let else` to handle the variant that isn't matched: ` else { todo!() }`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "// 因为右边的值可能不为 `Some`，而是 `None`，这种时候就不能进行匹配，也就是上面的代码遗漏了 `None` 的匹配。\n",
    "\n",
    "let value: Option<i32> = None;\n",
    "let Some(x) = value;\n",
    "println!(\"{x}\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`let` 语句在 Rust 中属于 不可驳模式匹配（irrefutable pattern）\n",
    "- **不可驳模式匹配**（irrefutable pattern）：它要求右侧的表达式 **必定** 能被左侧的模式完整匹配。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "let value: Option<i32> = None;\n",
    "\n",
    "if let Some(x) = value { // if let 允许匹配一种模式，而忽略其余的模式( 可驳模式匹配 )\n",
    "    println!(\"{}\", x);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### let-else(Rust 1.65 新增)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`let-else` 让 `let` 也能执行可驳匹配：当匹配失败时必须通过发散语句（如 `return`/`break`/`panic`）退出，而成功绑定的变量作用域会延伸到整个 `let` 之后的代码块中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::str::FromStr;\n",
    "\n",
    "fn get_count_item(s: &str) -> (u64, &str) {\n",
    "    let mut it = s.split(' ');\n",
    "    let (Some(count_str), Some(item)) = (it.next(), it.next()) else {\n",
    "        panic!(\"Can't segment count item pair: '{s}'\");\n",
    "    };\n",
    "    let Ok(count) = u64::from_str(count_str) else {\n",
    "        panic!(\"Can't parse integer: '{count_str}'\");\n",
    "    };\n",
    "    // error: `else` clause of `let...else` does not diverge\n",
    "    // let Ok(count) = u64::from_str(count_str) else { 0 };\n",
    "    (count, item)\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    assert_eq!(get_count_item(\"3 chairs\"), (3, \"chairs\"));\n",
    "}\n",
    "\n",
    "main()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// if let 写法里的 x 只能在 if 分支内使用\n",
    "\n",
    "let value: Option<i32> = Some(1);\n",
    "if let Some(x) = value {\n",
    "    println!(\"{}\", x);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    }
   ],
   "source": [
    "// let-else 写法里的 x 则可以在 let 之外使用\n",
    "\n",
    "let value: Option<i32> = Some(1);\n",
    "let Some(x) = value else { return ; };\n",
    "println!(\"{}\", x);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 全模式列表\n",
    "\n",
    "- https://course.rs/basic/match-pattern/all-patterns.html\n",
    "- https://practice-zh.course.rs/pattern-match/patterns.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/pattern-match/patterns.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 模式类别                     | 核心语法                               | 示例（简化）                                                 | 关键说明                                                     |\n",
    "| ---------------------------- | -------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |\n",
    "| 匹配字面值                   | `match value { literal => ... }`       | `match 1 { 1 => \"one\", _ => \"other\" }`                       | 适用于精确比对特定常量；未匹配用 `_` 覆盖。                  |\n",
    "| 匹配命名变量（遮蔽）         | `Some(y) => ...`                       | `match Some(5) { Some(y) => println!(\"{y}\") , _ => () }`     | 分支内的新变量会遮蔽外围同名变量；匹配成功后绑定内部值。     |\n",
    "| 单分支多模式                 | `pattern_1 \\| pattern_2`                | `match x { 1 \\| 2 => println!(\"one or two\"), _ => println!(\"other\") }` | 使用逻辑“或”将多个模式合并到同一分支。                       |\n",
    "| 区间匹配                     | `start..=end`                          | `match 5 { 1..=5 => ... , _ => ... }`                        | 仅支持数字与字符；闭区间。                                   |\n",
    "| 解构结构体                   | `let Struct { field, ... }`            | `let Point { x, y } = p;`                                    | 字段名简写自动绑定同名变量；可混用字面值测试。               |\n",
    "| 匹配特定结构体字段           | `Struct { field: value, ... }`         | `match p { Point { y: 0, x } => ... }`                       | 可固定部分字段的取值，其他字段照常绑定。                     |\n",
    "| 解构枚举                     | `Enum::Variant(pattern)`               | `match msg { Message::Move { x, y } => ... }`                | 模式需与枚举变体结构一致；无数据变体只能字面匹配。           |\n",
    "| 解构嵌套枚举/结构体          | 组合前两类                             | `Message::ChangeColor(Color::Rgb(r,g,b))`                    | 可多层级匹配，逐层拆解内部值。                               |\n",
    "| 解构结构体 + 元组            | 混合模式                               | `let ((a,b), Point { x, y }) = data;`                        | 多种类型可同时解构，便于提取深层值。                         |\n",
    "| 解构数组（定长）             | `[a, b, ...]`                          | `let [x, y] = [114, 514];`                                   | 模式长度需与数组长度一致。                                   |\n",
    "| 解构切片（不定长）           | `[first, ..]` / `[.., last]`           | `if let [x, ..] = slice { ... }`                             | 使用 `..` 忽略剩余元素；支持 `matches!` 辅助宏。             |\n",
    "| 忽略整个值                   | `_`                                    | `fn foo(_: i32, y: i32) { ... }`                             | `_` 不绑定值，消除“未使用变量”警告。                         |\n",
    "| 忽略部分值                   | `Some(_)`、`(_, _, value, ..)`         | `match (Some(5), None) { (Some(_), Some(_)) => ... , _ => ... }` | `_` 可多处使用以忽略具体位置。                               |\n",
    "| 仅忽略命名变量               | `_var`                                 | `let _x = compute();`                                        | 仍产生绑定但抑制未使用警告；与 `_`（完全不绑定）不同。       |\n",
    "| 忽略剩余字段/元素            | `..`                                   | `Point { x, .. }` / `(first, .., last)`                      | 在结构体或元组中忽略其余成员；每个模式中只能出现一次。       |\n",
    "| 匹配守卫                     | `pattern if condition`                 | `match Some(4) { Some(x) if x < 5 => ... }`                  | `if` 条件进一步过滤命中的模式；作用于该分支所有子模式。      |\n",
    "| 避免遮蔽的守卫               | `Some(n) if n == outer`                | `match x { Some(n) if n == y => ... }`                       | 守卫中可引用外部变量而不引入新绑定。                         |\n",
    "| 守卫与多模式                 | `(pattern_1 \\| pattern_2) if condition` | `match x { 4 \\| 5 \\| 6 if allow => println!(\"allowed\"), _ => println!(\"denied\") }` | 匹配守卫作用于整组 `|` 模式，先命中任一模式，再判断 `if` 条件。 |\n",
    "| `@` 绑定                     | `binding @ subpattern`                 | `Message::Hello { id: id_var @ 3..=7 }`                      | 同时测试子模式并保存匹配值；适合范围检测后复用变量。         |\n",
    "| `@` 绑定 + 解构 (Rust 1.56+) | `p @ Pattern { ... }`                  | `let p @ Point { x: px, y: py } = point;`                    | 绑定整体值供后续使用，同时拆解内部字段。                     |\n",
    "| `@` 与多模式 (Rust 1.53+)    | `binding @ (pattern_1 \\| pattern_2)`    | `match n { num @ (1 \\| 2) => println!(\"{num}\"), _ => () }`    | 为整组模式绑定同一个变量；需 Rust 1.53+。                    |\n",
    "\n",
    "> 提示：所有模式匹配都要求被匹配值与模式类型兼容；对可驳模式（可能失败）使用 `if let`、`let-else` 或完整 `match` 来妥善处理失败分支。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 匹配字面值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "one\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 希望代码获得特定的具体值\n",
    "\n",
    "let x = 1;\n",
    "\n",
    "match x {\n",
    "    1 => println!(\"one\"),\n",
    "    2 => println!(\"two\"),\n",
    "    3 => println!(\"three\"),\n",
    "    _ => println!(\"anything\"),\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 匹配命名变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Matched, y = 5\n",
      "at the end: x = Some(5), y = 10\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let x = Some(5);\n",
    "    let y = 10;\n",
    "\n",
    "    match x {\n",
    "        Some(50) => println!(\"Got 50\"),\n",
    "        Some(y) => println!(\"Matched, y = {:?}\", y), // Some(y)匹配任何 Some 中的值\n",
    "        _ => println!(\"Default case, x = {:?}\", x),\n",
    "    }\n",
    "\n",
    "    println!(\"at the end: x = {:?}, y = {:?}\", x, y);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Matched, value = 5\n",
      "at the end: x = Some(5), y = 10\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let x = Some(5);\n",
    "    let y = 10;\n",
    "\n",
    "    match x {\n",
    "        Some(50) => println!(\"Got 50\"),\n",
    "        Some(value) => println!(\"Matched, value = {:?}\", value),\n",
    "        _ => println!(\"Default case, x = {:?}\", x),\n",
    "    }\n",
    "\n",
    "    println!(\"at the end: x = {:?}, y = {:?}\", x, y);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 单分支多模式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "one or two\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "let x = 1;\n",
    "\n",
    "match x {\n",
    "    1 | 2 => println!(\"one or two\"), // 代表 或的意思\n",
    "    3 => println!(\"three\"),\n",
    "    _ => println!(\"anything\"),\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 通过序列 `..=` 匹配值的范围"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "one through five\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "let x = 5;\n",
    "\n",
    "match x {\n",
    "    1..=5 => println!(\"one through five\"), // ..= 语法允许你匹配一个闭区间序列内的值, `1 | 2 | 3 | 4 | 5`; 序列只允许用于数字或字符类型\n",
    "    _ => println!(\"something else\"),\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "early ASCII letter\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "let x = 'c';\n",
    "\n",
    "match x {\n",
    "    'a'..='j' => println!(\"early ASCII letter\"),\n",
    "    'k'..='z' => println!(\"late ASCII letter\"),\n",
    "    _ => println!(\"something else\"),\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 解构并分解值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 解构结构体"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Point {\n",
    "    x: i32,\n",
    "    y: i32,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let p = Point { x: 0, y: 7 };\n",
    "\n",
    "    let Point { x: a, y: b } = p; // 模式中的变量名不必与结构体中的字段名一致\n",
    "    assert_eq!(0, a);\n",
    "    assert_eq!(7, b);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Point {\n",
    "    x: i32,\n",
    "    y: i32,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let p = Point { x: 0, y: 7 };\n",
    "\n",
    "    let Point { x, y } = p; // 只需列出结构体字段的名称，则模式创建的变量会有相同的名称\n",
    "    assert_eq!(0, x);\n",
    "    assert_eq!(7, y);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "On the y axis at 7\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let p = Point { x: 0, y: 7 };\n",
    "\n",
    "    match p {\n",
    "        Point { x, y: 0 } => println!(\"On the x axis at {}\", x),\n",
    "        Point { x: 0, y } => println!(\"On the y axis at {}\", y),\n",
    "        Point { x, y } => println!(\"On neither axis: ({}, {})\", x, y),\n",
    "    }\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 解构枚举"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Change the color to red 0, green 160, and blue 255\n"
     ]
    }
   ],
   "source": [
    "enum Message {\n",
    "    Quit,\n",
    "    Move { x: i32, y: i32 },\n",
    "    Write(String),\n",
    "    ChangeColor(i32, i32, i32),\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let msg = Message::ChangeColor(0, 160, 255);\n",
    "\n",
    "    match msg {\n",
    "        Message::Quit => {\n",
    "            println!(\"The Quit variant has no data to destructure.\")\n",
    "        }\n",
    "        Message::Move { x, y } => {\n",
    "            println!(\n",
    "                \"Move in the x direction {} and in the y direction {}\",\n",
    "                x,\n",
    "                y\n",
    "            );\n",
    "        }\n",
    "        Message::Write(text) => println!(\"Text message: {}\", text),\n",
    "        Message::ChangeColor(r, g, b) => { // 模式匹配一样要类型相同\n",
    "            println!(\n",
    "                \"Change the color to red {}, green {}, and blue {}\",\n",
    "                r,\n",
    "                g,\n",
    "                b\n",
    "            )\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 解构嵌套的结构体和枚举"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Change the color to hue 0, saturation 160, and value 255\n"
     ]
    }
   ],
   "source": [
    "enum Color {\n",
    "   Rgb(i32, i32, i32),\n",
    "   Hsv(i32, i32, i32),\n",
    "}\n",
    "\n",
    "enum Message {\n",
    "    Quit,\n",
    "    Move { x: i32, y: i32 },\n",
    "    Write(String),\n",
    "    ChangeColor(Color),\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));\n",
    "\n",
    "    match msg {\n",
    "        Message::ChangeColor(Color::Rgb(r, g, b)) => {\n",
    "            println!(\n",
    "                \"Change the color to red {}, green {}, and blue {}\",\n",
    "                r,\n",
    "                g,\n",
    "                b\n",
    "            )\n",
    "        }\n",
    "        Message::ChangeColor(Color::Hsv(h, s, v)) => {\n",
    "            println!(\n",
    "                \"Change the color to hue {}, saturation {}, and value {}\",\n",
    "                h,\n",
    "                s,\n",
    "                v\n",
    "            )\n",
    "        }\n",
    "        _ => ()\n",
    "    }\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 解构结构体和元组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Point {\n",
    "     x: i32,\n",
    "     y: i32,\n",
    " }\n",
    "\n",
    "let ((feet, inches), Point {x, y}) = ((3, 10), Point { x: 3, y: -10 });"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 解构数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 定长数组\n",
    "\n",
    "let arr: [u16; 2] = [114, 514];\n",
    "let [x, y] = arr;\n",
    "\n",
    "assert_eq!(x, 114);\n",
    "assert_eq!(y, 514);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 不定长数组\n",
    "\n",
    "fn main() {\n",
    "    let arr: &[u16] = &[114, 514];\n",
    "\n",
    "    // -----------------------------\n",
    "    // 示例 1：切片解构匹配第一个元素\n",
    "    // -----------------------------\n",
    "    // `if let` 会尝试把 `arr` 解构成形如 `[x, ..]` 的切片模式：\n",
    "    // - `x` 捕获首元素（类型为 `&u16`，因为匹配的是切片引用）\n",
    "    // - `..` 表示“剩余的任意长度切片”，本例中就是 `[514]`\n",
    "    // 只有当模式匹配成功（切片非空）才会进入代码块。\n",
    "    if let [x, ..] = arr {\n",
    "        assert_eq!(x, &114); // 匹配成功，首元素是 114\n",
    "    }\n",
    "\n",
    "    // -----------------------------\n",
    "    // 示例 2：切片解构匹配最后一个元素\n",
    "    // -----------------------------\n",
    "    // `[.., y]` 模式：\n",
    "    // - `[..]` 捕获前面任意长度的前缀\n",
    "    // - `y` 捕获最后一个元素（同样是 `&u16`）\n",
    "    if let &[.., y] = arr {\n",
    "        assert_eq!(y, 514); // 匹配成功，末元素是 514\n",
    "    }\n",
    "\n",
    "    // -----------------------------\n",
    "    // 示例 3：在空切片上验证模式匹配\n",
    "    // -----------------------------\n",
    "    let arr: &[u16] = &[];\n",
    "\n",
    "    // `matches!` 宏可以快速测试某个表达式是否匹配指定模式。\n",
    "    // `[..]`（或简单写成 `[]`）能匹配任何切片，包括空切片。\n",
    "    assert!(matches!(arr, [..]));\n",
    "\n",
    "    // `[x, ..]` 要求至少有一个元素才能匹配。\n",
    "    // 空切片与该模式不匹配。\n",
    "    assert!(!matches!(arr, [x, ..]));\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 在引用切片（`&[T]`）上使用切片模式时，绑定的元素类型会自动带引用：`[x, ..]` 中的 `x` 类型为 `&T`。\n",
    "- `..` 可以出现在切片模式的开头、中间或结尾，用于“吞掉”任意数量的剩余元素；但整个模式必须保证元素个数是确定的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 忽略模式中的值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用 `_` 忽略整个值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This code only uses the y parameter: 4\n"
     ]
    }
   ],
   "source": [
    "// 可以将其用于函数参数中\n",
    "\n",
    "fn foo(_: i32, y: i32) {\n",
    "    println!(\"This code only uses the y parameter: {}\", y);\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    foo(3, 4);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用嵌套的 _ 忽略部分值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Can't overwrite an existing customized value\n",
      "setting is Some(5)\n"
     ]
    }
   ],
   "source": [
    "let mut setting_value = Some(5);\n",
    "let new_setting_value = Some(10);\n",
    "\n",
    "match (setting_value, new_setting_value) {\n",
    "    (Some(_), Some(_)) => {\n",
    "        println!(\"Can't overwrite an existing customized value\");\n",
    "    }\n",
    "    _ => {\n",
    "        setting_value = new_setting_value;\n",
    "    }\n",
    "}\n",
    "\n",
    "println!(\"setting is {:?}\", setting_value);\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Some numbers: 2, 8, 32\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "let numbers = (2, 4, 8, 16, 32);\n",
    "\n",
    "match numbers {\n",
    "    (first, _, third, _, fifth) => { // 模式匹配一定要类型相同，因此匹配 numbers 元组的模式，也必须有五个值\n",
    "        println!(\"Some numbers: {}, {}, {}\", first, third, fifth)\n",
    "    },\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用下划线开头忽略未使用的变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "let _x = 5;\n",
    "let y = 10;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意, 只使用 `_` 和使用以下划线开头的名称有些微妙的不同：比如 **`_x` 仍会将值绑定到变量，而 `_` 则完全不会绑定**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "unused variable: `y`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[unused_variables] Error:\u001b[0m unused variable: `y`"
     ]
    },
    {
     "ename": "Error",
     "evalue": "borrow of partially moved value: `s`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0382] Error:\u001b[0m borrow of partially moved value: `s`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_37:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249mi\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mS\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;68m┬\u001b[0m\u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m help: borrow this binding in the pattern to avoid moving the value: `ref `",
      " \u001b[38;5;240m  │\u001b[0m              \u001b[38;5;54m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m              \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m value partially moved here",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m7 │\u001b[0m \u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m?\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                  \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                  \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m value borrowed here after partial move",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let s = Some(String::from(\"Hello!\"));\n",
    "\n",
    "if let Some(_s) = s {\n",
    "    println!(\"found a string\");\n",
    "}\n",
    "\n",
    "println!(\"{:?}\", s);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "found a string\n",
      "Some(\"Hello!\")\n"
     ]
    }
   ],
   "source": [
    "let s = Some(String::from(\"Hello!\"));\n",
    "\n",
    "if let Some(_) = s { // 只使用下划线本身，则并不会绑定值，因为 s 没有被移动进 _：\n",
    "    println!(\"found a string\");\n",
    "}\n",
    "\n",
    "println!(\"{:?}\", s);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 用 `..` 忽略剩余值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x is 0\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "struct Point {\n",
    "    x: i32,\n",
    "    y: i32,\n",
    "    z: i32,\n",
    "}\n",
    "\n",
    "let origin = Point { x: 0, y: 0, z: 0 };\n",
    "\n",
    "match origin {\n",
    "    Point { x, .. } => println!(\"x is {}\", x), // 列出了 x 值，接着使用了 .. 模式来忽略其它字段\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Some numbers: 2, 32\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let numbers = (2, 4, 8, 16, 32);\n",
    "\n",
    "    match numbers {\n",
    "        (first, .., last) => { // 用 .. 来忽略元组中间的某些值\n",
    "            println!(\"Some numbers: {}, {}\", first, last);\n",
    "        },\n",
    "    }\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "`..` can only be used once per tuple pattern",
     "output_type": "error",
     "traceback": [
      "        (.., second, ..) => { ",
      "\u001b[91m                     ^^\u001b[0m \u001b[94mcan only be used once per tuple pattern\u001b[0m",
      "        (.., second, ..) => { ",
      "\u001b[91m         ^^\u001b[0m \u001b[94mpreviously used here\u001b[0m",
      "`..` can only be used once per tuple pattern"
     ]
    }
   ],
   "source": [
    "// 使用 .. 必须是无歧义的. Rust 无法判断，second 应该匹配 numbers 中的第几个元素，因此这里使用两个 .. 模式，是有很大歧义的！\n",
    "\n",
    "fn main() {\n",
    "    let numbers = (2, 4, 8, 16, 32);\n",
    "\n",
    "    match numbers {\n",
    "        (.., second, ..) => { \n",
    "            println!(\"Some numbers: {}\", second)\n",
    "        },\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 匹配守卫提供的额外条件"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**匹配守卫**（*match guard*）是一个位于 `match` 分支模式之后的额外 `if` 条件，它能为分支模式提供更进一步的匹配条件。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "less than five: 4\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "let num = Some(4);\n",
    "\n",
    "match num {\n",
    "    Some(x) if x < 5 => println!(\"less than five: {}\", x), // 这个条件可以使用模式中创建的变量\n",
    "    Some(x) => println!(\"{}\", x),\n",
    "    None => (),\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在[之前](https://course.rs/basic/match-pattern/all-patterns.html#匹配命名变量)，我们提到可以使用匹配守卫来解决模式中变量覆盖的问题，那里 `match` 表达式的模式中新建了一个变量而不是使用 `match` 之外的同名变量。内部变量覆盖了外部变量，意味着此时不能够使用外部变量的值，下面代码展示了如何使用匹配守卫修复这个问题。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Default case, x = Some(5)\n",
      "at the end: x = Some(5), y = 10\n"
     ]
    }
   ],
   "source": [
    "let x = Some(5);\n",
    "let y = 10;\n",
    "\n",
    "match x {\n",
    "    Some(50) => println!(\"Got 50\"),\n",
    "    Some(n) if n == y => println!(\"Matched, n = {}\", n), // 第二个匹配分支由于没有新建局部变量 y，因此在匹配守卫中使用的是外部的 y。\n",
    "    _ => println!(\"Default case, x = {:?}\", x),\n",
    "}\n",
    "\n",
    "println!(\"at the end: x = {:?}, y = {}\", x, y);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "为什么守卫能避免遮蔽？\n",
    "- 模式 `Some(n)` 确实引入了局部变量 `n`，它只在这个分支内有效。\n",
    "- **守卫不是模式**，它只是额外条件，所以不会再新建变量。\n",
    "- 守卫中的 `y` 没有在模式里声明，因此直接引用的是外层的 `y = 10`。也就是说，这里没有出现新的 `y`，更谈不上遮蔽。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Matched, n = 5\n",
      "at the end: x = Some(5), y = 5\n"
     ]
    }
   ],
   "source": [
    "let x = Some(5);\n",
    "let y = 5;\n",
    "\n",
    "match x {\n",
    "    Some(50) => println!(\"Got 50\"),\n",
    "    Some(n) if n == y => println!(\"Matched, n = {}\", n), // 第二个匹配分支由于没有新建局部变量 y，因此在匹配守卫中使用的是外部的 y。\n",
    "    _ => println!(\"Default case, x = {:?}\", x),\n",
    "}\n",
    "\n",
    "println!(\"at the end: x = {:?}, y = {}\", x, y);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "no\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "let x = 4;\n",
    "let y = false;\n",
    "\n",
    "match x {\n",
    "    (4 | 5 | 6) if y => println!(\"yes\"), // 匹配守卫 if y 作用于 4、5 和 6 ，在满足 x 属于 4 | 5 | 6 后才会判断 y 是否为 true\n",
    "    _ => println!(\"no\"),\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### @绑定"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "@（读作 at）运算符允许为一个字段绑定另外一个变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found an id in range: 5\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 当你既想要限定分支范围，又想要使用分支的变量时，就可以用 @ 来绑定到一个新的变量上，实现想要的功能。\n",
    "\n",
    "enum Message {\n",
    "    Hello { id: i32 },\n",
    "}\n",
    "\n",
    "let msg = Message::Hello { id: 5 };\n",
    "\n",
    "match msg {\n",
    "    Message::Hello { id: id_variable @ 3..=7 } => { // 将其值绑定到 id_variable 变量中以便此分支中相关的代码可以使用它\n",
    "        println!(\"Found an id in range: {}\", id_variable)\n",
    "    },\n",
    "    Message::Hello { id: 10..=12 } => { // 只在模式中指定了一个范围，id 字段的值可以是 10、11 或 12，不过这个模式的代码并不知情也不能使用 id 字段中的值，因为没有将 id 值保存进一个变量。\n",
    "        println!(\"Found an id in another range\")\n",
    "    },\n",
    "    Message::Hello { id } => { // 最后一个分支指定了一个没有范围的变量，此时确实拥有可以用于分支代码的变量 id，因为这里使用了结构体字段简写语法。\n",
    "        println!(\"Found some other id: {}\", id)\n",
    "    },\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**@前绑定后解构(Rust 1.56 新增)**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#[derive(Debug)]\n",
    "struct Point {\n",
    "    x: i32,\n",
    "    y: i32,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    // 绑定新变量 `p`，同时对 `Point` 进行解构\n",
    "    let p @ Point {x: px, y: py } = Point {x: 10, y: 23};\n",
    "    println!(\"x: {}, y: {}\", px, py);\n",
    "    println!(\"{:?}\", p);\n",
    "\n",
    "\n",
    "    let point = Point {x: 10, y: 5};\n",
    "    if let p @ Point {x: 10, y} = point {\n",
    "        println!(\"x is 10 and y is {} in {:?}\", y, p);\n",
    "    } else {\n",
    "        println!(\"x was not 10 :(\");\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**@新特性(Rust 1.53 新增)**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "variable `num` is not bound in all patterns",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0408] Error:\u001b[0m variable `num` is not bound in all patterns",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_50:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100mm\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m@\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m2\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m       \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m variable not in all patterns",
      " \u001b[38;5;240m  │\u001b[0m                   \u001b[38;5;54m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                   \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m pattern doesn't bind `num`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "used binding `num` is possibly-uninitialized",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0381] Error:\u001b[0m used binding `num` is possibly-uninitialized",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_50:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100mm\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m@\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m binding initialized here in some conditions",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;68m│\u001b[0m   ",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m binding declared here but left uninitialized",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                            \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                             \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `num` used here but it is possibly-uninitialized",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    match 1 {\n",
    "        num @ 1 | 2 => {\n",
    "            println!(\"{}\", num);\n",
    "        }\n",
    "        _ => {}\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    match 1 {\n",
    "        num @ (1 | 2) => {\n",
    "            println!(\"{}\", num);\n",
    "        }\n",
    "        _ => {}\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.7. 方法 Method\n",
    "\n",
    "- https://course.rs/basic/method.html\n",
    "- https://practice-zh.course.rs/method.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/method.md\n",
    "\n",
    "\n",
    "在 Rust 中，方法与其他语言的 class 方法概念相近，同样通过 `object.method()` 调用，但它们通常与结构体、枚举和特征紧密结合"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Rust 使用 impl 来定义方法，例如以下代码：\n",
    "\n",
    "struct Circle {\n",
    "    x: f64,\n",
    "    y: f64,\n",
    "    radius: f64,\n",
    "}\n",
    "\n",
    "impl Circle {\n",
    "    // new是Circle的关联函数，因为它的第一个参数不是self，且new并不是关键字\n",
    "    // 这种方法往往用于初始化当前结构体的实例\n",
    "    fn new(x: f64, y: f64, radius: f64) -> Circle {\n",
    "        Circle {\n",
    "            x: x,\n",
    "            y: y,\n",
    "            radius: radius,\n",
    "        }\n",
    "    }\n",
    "\n",
    "    // Circle的方法，&self表示借用当前的Circle结构体\n",
    "    fn area(&self) -> f64 {\n",
    "        std::f64::consts::PI * (self.radius * self.radius)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "// 其它语言中所有定义都在 class 中，但是 Rust 的对象定义和方法定义是分离的，这种数据和使用分离的方式，会给予使用者极高的灵活度。\n",
    "\n",
    "+-----------------------------+    +------------------------------+\n",
    "| Classes in other languages  |    | Struct and enum in Rust      |\n",
    "|                             |    |                              |\n",
    "| class File {                |    | struct File {                |\n",
    "|   +---------------------+   |    |   +---------------------+    |\n",
    "|   |        Data         |   |    |   |        Data         |    |\n",
    "|   +---------------------+   |    |   +---------------------+    |\n",
    "|   |      Methods        |   |    | }                            |\n",
    "|   +---------------------+   |    |                              |\n",
    "| }                           |    | impl File {                  |\n",
    "|                             |    |   +---------------------+    |\n",
    "+-----------------------------+    |   |      Methods        |    |\n",
    "                                   |   +---------------------+    |\n",
    "                                   | }                            |\n",
    "                                   +------------------------------+"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`impl Rectangle {}` 表示为 `Rectangle` 实现方法（`impl` 是实现 *implementation* 的缩写），这样的写法表明 `impl` 语句块中的一切都是跟 `Rectangle` 相关联的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#[derive(Debug)]\n",
    "struct Rectangle { // 定义了一个 Rectangle 结构体\n",
    "    width: u32,\n",
    "    height: u32,\n",
    "}\n",
    "\n",
    "impl Rectangle {\n",
    "    fn area(&self) -> u32 { // 在其上定义了一个 area 方法，用于计算该矩形的面积\n",
    "        self.width * self.height\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let rect1 = Rectangle { width: 30, height: 50 };\n",
    "\n",
    "    println!(\n",
    "        \"The area of the rectangle is {} square pixels.\",\n",
    "        rect1.area()\n",
    "    );\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The area of the rectangle is 1500 square pixels.\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### self、&self 和 &mut self"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 `impl` 块内，`Self` 代表实现方法的结构体类型，`self` 代表该类型的实例；`&self` 是 `self: &Self` 的简写。\n",
    "\n",
    "`self` 形参同样遵循所有权规则：\n",
    "\n",
    "- `self`：转移实例所有权，少用，常见于将对象转换成其他对象时。\n",
    "- `&self`：不可变借用，读取数据而不修改。\n",
    "- `&mut self`：可变借用，允许在方法中修改实例。\n",
    "\n",
    "选择 `&self` 的理由与函数使用 `&Type` 相同：无需取得所有权，也不改变实例。\n",
    "\n",
    "使用方法（而非自由函数）的好处：\n",
    "\n",
    "- 避免在签名中重复写类型，代码更简洁。\n",
    "- 代码组织更内聚，利于维护与阅读。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 方法名跟结构体字段名相同"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#[derive(Debug)]\n",
    "struct Rectangle { // 定义了一个 Rectangle 结构体\n",
    "    width: u32,\n",
    "    height: u32,\n",
    "}\n",
    "\n",
    "impl Rectangle { // 在 Rust 中，允许方法名跟结构体的字段名相同\n",
    "    fn width(&self) -> bool {\n",
    "        self.width > 0\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let rect1 = Rectangle {\n",
    "        width: 30,\n",
    "        height: 50,\n",
    "    };\n",
    "\n",
    "    if rect1.width() { // 当我们使用 rect1.width() 时，Rust 知道我们调用的是它的方法，\n",
    "        println!(\"The rectangle has a nonzero width; it is {}\", rect1.width); // 如果使用 rect1.width，则是访问它的字段。\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The rectangle has a nonzero width; it is 30\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 一般来说，方法跟字段同名，往往适用于实现 getter 访问器\n",
    "\n",
    "mod my { // 当从模块外部访问结构体时，结构体的字段默认是私有的，其目的是隐藏信息（封装）\n",
    "    pub struct Rectangle {\n",
    "        width: u32, // 因为 width 字段是私有的，当用户访问 rect1.width 字段时，就会报错\n",
    "        pub height: u32,\n",
    "    }\n",
    "\n",
    "    impl Rectangle { // 想要从模块外部获取 Rectangle 的字段，只需把它的 new， width 和 height 方法设置为公开可见\n",
    "        pub fn new(width: u32, height: u32) -> Self { // Self 指代的就是被实现方法的结构体 Rectangle\n",
    "            Rectangle { width, height }\n",
    "        }\n",
    "        pub fn width(&self) -> u32 {\n",
    "            return self.width;\n",
    "        }\n",
    "        pub fn height(&self) -> u32 {\n",
    "            return self.height;\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "let rect1 = my::Rectangle::new(30, 50);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "默认的可见性（私有的）可以通过 `pub` 进行覆盖，这样对于模块外部来说，就可以直接访问使用 `pub` 修饰的字段而无需通过访问器。这种可见性仅当从定义结构的模块外部访问时才重要，并且具有隐藏信息（封装）的目的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "30\n",
      "50\n",
      "50\n"
     ]
    }
   ],
   "source": [
    "println!(\"{}\", rect1.width()); // OK\n",
    "println!(\"{}\", rect1.height()); // OK\n",
    "\n",
    "println!(\"{}\", rect1.height); // OK"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "field `width` of struct `my::Rectangle` is private",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0616] Error:\u001b[0m field `width` of struct `my::Rectangle` is private",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_58:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;54mw\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mE\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;100m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m                        \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m private field",
      " \u001b[38;5;240m  │\u001b[0m                           \u001b[38;5;100m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m                           \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m help: a method `width` also exists, call it with parentheses: `()`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "println!(\"{}\", rect1.width); // Error - the visibility of field defaults to private"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> `->` 运算符到哪去了\n",
    "\n",
    "在 C/C++ 语言中，有两个不同的运算符来调用方法：`.` 直接在对象上调用方法，而 `->` 在一个对象的指针上调用方法，这时需要先解引用指针。换句话说，如果 `object` 是一个指针，那么 `object->something()` 和 `(*object).something()` 是一样的。\n",
    "\n",
    "Rust 并没有一个与 `->` 等效的运算符；相反，Rust 有一个叫 **自动引用和解引用**的功能。方法调用是 Rust 中少数几个拥有这种行为的地方。\n",
    "\n",
    "他是这样工作的：当使用 `object.something()` 调用方法时，Rust 会自动为 `object` 添加 `&`（视可见性添加`&mut`)、 `*` 以便使 `object` 与方法签名匹配。也就是说，这些代码是等价的：\n",
    "\n",
    "```rust\n",
    "p1.distance(&p2);\n",
    "(&p1).distance(&p2);\n",
    "```\n",
    "\n",
    "第一行看起来简洁的多。这种自动引用的行为之所以有效，是因为方法有一个明确的接收者———— `self` 的类型。在给出接收者和方法名的前提下，Rust 可以明确地计算出方法是仅仅读取（`&self`），做出修改（`&mut self`）或者是获取所有权（`self`）。事实上，Rust 对方法接收者的隐式借用让所有权在实践中更友好。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 带有多个参数的方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Can rect1 hold rect2? true\n",
      "Can rect1 hold rect3? false\n"
     ]
    }
   ],
   "source": [
    "impl Rectangle {\n",
    "    fn area(&self) -> u32 {\n",
    "        self.width * self.height\n",
    "    }\n",
    "\n",
    "    fn can_hold(&self, other: &Rectangle) -> bool {\n",
    "        self.width > other.width && self.height > other.height\n",
    "    }\n",
    "}\n",
    "\n",
    "\n",
    "let rect1 = Rectangle { width: 30, height: 50 };\n",
    "let rect2 = Rectangle { width: 10, height: 40 };\n",
    "let rect3 = Rectangle { width: 60, height: 45 };\n",
    "\n",
    "println!(\"Can rect1 hold rect2? {}\", rect1.can_hold(&rect2));\n",
    "println!(\"Can rect1 hold rect3? {}\", rect1.can_hold(&rect3));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 关联函数\n",
    "\n",
    "- **定义构造器**：在 `impl` 块内编写不带 `self` 参数的函数即可，用于接收参数并返回结构体实例。\n",
    "- **关联函数**：没有 `self` 的 `impl` 内函数称为“关联函数”，它与结构体紧密关联，但不是方法。\n",
    "- **调用方式**：关联函数通过 `::` 调用（例如 `Rectangle::new(3, 3)`），因为它位于结构体的命名空间。\n",
    "- **命名约定**：惯例使用 `new` 作为构造器名称，Rust 特意没有将 `new` 设为关键字，保留设计灵活性。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> AI:\n",
    "\n",
    "在 Rust 中，`new` 只是一个普通的关联函数名字，并没有“特殊含义”或语言层面的魔法。\n",
    "\n",
    "**为什么绝大多数 new 都返回值？**\n",
    "\n",
    "虽然语法不强制，但**约定俗成**的“构造函数”会写成：\n",
    "\n",
    "```rust\n",
    "impl Foo {\n",
    "    fn new() -> Self {\n",
    "        Foo { /* 初始化字段 */ }\n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "原因主要有：\n",
    "\n",
    "1. **语义清晰**：看到 `new`，就知道它会创建一个新实例。\n",
    "2. **链式调用**：常常配合 `Result<Self, E>`，允许在构造时做校验并返回错误。\n",
    "3. **可与 `Default`、`From` 等 trait 互补**：`new`/`default` 组合让初始化方式多样化。\n",
    "\n",
    "并且因为 Rust 没有类似 C++ 的构造器语法，`fn new() -> Self` 成了社区默认的“常规构造”模式。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 多个 impl 定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "impl Rectangle {\n",
    "    fn area(&self) -> u32 {\n",
    "        self.width * self.height\n",
    "    }\n",
    "}\n",
    "\n",
    "impl Rectangle {\n",
    "    fn can_hold(&self, other: &Rectangle) -> bool {\n",
    "        self.width > other.width && self.height > other.height\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 为枚举实现方法\n",
    "\n",
    "枚举类型之所以强大，不仅仅在于它好用、可以[同一化类型](https://course.rs/basic/compound-type/enum.html#同一化类型)，还在于，我们可以像结构体一样，为枚举实现方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Message.Write: hello\n"
     ]
    }
   ],
   "source": [
    "enum Message {\n",
    "    Quit,\n",
    "    Move { x: i32, y: i32 },\n",
    "    Write(String),\n",
    "    ChangeColor(i32, i32, i32),\n",
    "}\n",
    "\n",
    "impl Message {\n",
    "    fn call(&self) {\n",
    "        match self {\n",
    "            Message::Quit => println!(\"quit\"),\n",
    "            Message::Move { x, y } => println!(\"move to ({x}, {y})\"),\n",
    "            Message::Write(text) => println!(\"Message.Write: {text}\"),\n",
    "            Message::ChangeColor(r, g, b) => println!(\"color -> ({r}, {g}, {b})\"),\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "\n",
    "let m = Message::Write(String::from(\"hello\"));\n",
    "m.call();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 对枚举的变体数据要通过解构（`match` / `if let` / `while let` 等）来访问，而不能像访问结构体字段那样写 `self.Write`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.8. 泛型和特征 / Generics and Traits"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 泛型 Generics\n",
    "\n",
    "- https://course.rs/basic/trait/generic.html\n",
    "- https://practice-zh.course.rs/generics-traits/generics.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/generics-traits/generics.md\n",
    "- https://practice-zh.course.rs/generics-traits/const-generics.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/generics-traits/const-generics.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 主题               | 核心要点                                                     |\n",
    "| ------------------ | ------------------------------------------------------------ |\n",
    "| 泛型的重要性与概念 | 泛型提供“通用炮管”，让同一函数/类型适配多种数据，减少重复代码；是静态多态的一种实现。 |\n",
    "| 基本用法与声明     | 泛型参数需在使用前声明（如 `fn largest<T>(...)`）；常习惯用单字母如 `T` 表示类型参数。 |\n",
    "| Trait 约束         | 非所有类型都支持操作，需要通过 Trait 约束限定能力，如 `T: PartialOrd`、`T: Add<Output = T>`。 |\n",
    "| 显式类型参数       | 当编译器无法推断泛型类型时，可用“涡轮鱼”语法显式指定：`create_and_print::<i64>()`。 |\n",
    "| 结构体中的泛型     | 通过 `struct Point<T>` 定义字段为泛型；若不同字段需要不同类型，用多个参数如 `Point<T, U>`。 |\n",
    "| 枚举中的泛型       | `Option<T>`、`Result<T, E>` 等利用泛型传递任意类型的值或错误，实现通用返回值模式。 |\n",
    "| 方法与泛型         | `impl<T> Point<T>` 可为泛型结构体实现方法；方法自身也可再声明新的泛型参数（如 `mixup<V, W>`）。 |\n",
    "| 针对具体类型的实现 | 可为特定实例化提供专属方法，如 `impl Point<f32> { fn distance_from_origin(...) }`。 |\n",
    "| const 泛型         | `const N: usize` 允许对值做泛型化，解决数组长度等编译期常量问题，可与类型泛型组合使用。 |\n",
    "| const fn           | `const fn` 支持编译期求值，常与 const 泛型协作以提前计算常量（如缓冲区大小），但受安全限制。 |\n",
    "| 性能与单态化       | Rust 在编译期对泛型单态化（monomorphization），生成各类型专用代码，实现零运行时开销，代价是更长编译时间和更大产物体积。 |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 在不支持泛型的编程语言中，通常需要为每一种类型编写一个函数：\n",
    "\n",
    "fn add_i8(a:i8, b:i8) -> i8 {\n",
    "    a + b\n",
    "}\n",
    "fn add_i32(a:i32, b:i32) -> i32 {\n",
    "    a + b\n",
    "}\n",
    "fn add_f64(a:f64, b:f64) -> f64 {\n",
    "    a + b\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    println!(\"add i8: {}\", add_i8(2i8, 3i8));\n",
    "    println!(\"add i32: {}\", add_i32(20, 30));\n",
    "    println!(\"add f64: {}\", add_f64(1.23, 1.23));\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 泛型就是一种多态\n",
    "\n",
    "fn add<T>(a:T, b:T) -> T {\n",
    "    a + b\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    println!(\"add i8: {}\", add(2i8, 3i8));\n",
    "    println!(\"add i32: {}\", add(20, 30));\n",
    "    println!(\"add f64: {}\", add(1.23, 1.23));\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 泛型详解"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "binary operation `>` cannot be applied to type `T`",
     "output_type": "error",
     "traceback": [
      "        if item > largest {",
      "\u001b[91m           ^^^^\u001b[0m \u001b[94mT\u001b[0m",
      "        if item > largest {",
      "\u001b[91m                  ^^^^^^^\u001b[0m \u001b[94mT\u001b[0m",
      "        if item > largest {",
      "\u001b[91m                ^\u001b[0m \u001b[94merror: binary operation `>` cannot be applied to type `T`\u001b[0m",
      "binary operation `>` cannot be applied to type `T`",
      "\u001b[1mhelp\u001b[0m: consider restricting type parameter `T` with trait `PartialOrd`\n\n: std::cmp::PartialOrd"
     ]
    }
   ],
   "source": [
    "fn largest<T>(list: &[T]) -> T { // 使用泛型参数，有一个先决条件，必需在使用前对其进行声明：\n",
    "    let mut largest = list[0];\n",
    "\n",
    "    for &item in list.iter() {\n",
    "        if item > largest {\n",
    "            largest = item;\n",
    "        }\n",
    "    }\n",
    "\n",
    "    largest\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let number_list = vec![34, 50, 25, 100, 65];\n",
    "\n",
    "    let result = largest(&number_list);\n",
    "    println!(\"The largest number is {}\", result);\n",
    "\n",
    "    let char_list = vec!['y', 'm', 'a', 'q'];\n",
    "\n",
    "    let result = largest(&char_list);\n",
    "    println!(\"The largest char is {}\", result);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "编译器建议我们给 `T` 添加一个类型限制：使用 `std::cmp::PartialOrd` 特征（Trait）对 `T` 进行限制，特征在下一节会详细介绍，现在你只要理解，该特征的目的就是让**类型实现可比较的功能**。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot add `T` to `T`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0369] Error:\u001b[0m cannot add `T` to `T`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_8:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m<\u001b[0m\u001b[38;5;249mT\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mT\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mT\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mT\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;37m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m help: consider restricting type parameter `T` with trait `Add`: `: std::ops::Add<Output = T>`",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68m+\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mb\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;54m┬\u001b[0m \u001b[38;5;68m┬\u001b[0m \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m T",
      " \u001b[38;5;240m  │\u001b[0m       \u001b[38;5;68m│\u001b[0m \u001b[38;5;100m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m       \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m error: cannot add `T` to `T`",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m T",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn add<T>(a:T, b:T) -> T {\n",
    "    a + b\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 同样的，不是所有 T 类型都能进行相加操作，因此我们需要用 std::ops::Add<Output = T> 对 T 进行限制：\n",
    "\n",
    "fn add<T: std::ops::Add<Output = T>>(a:T, b:T) -> T {\n",
    "    a + b\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 显式地指定泛型的类型参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "type annotations needed",
     "output_type": "error",
     "traceback": [
      "    create_and_print();",
      "\u001b[91m    ^^^^^^^^^^^^^^^^\u001b[0m \u001b[94mcannot infer type of the type parameter `T` declared on the function `create_and_print`\u001b[0m",
      "type annotations needed",
      "\u001b[1mhelp\u001b[0m: consider specifying the generic argument\n\n::<T>"
     ]
    }
   ],
   "source": [
    "use std::fmt::Display;\n",
    "\n",
    "fn create_and_print<T>() where T: From<i32> + Display {\n",
    "    let a: T = 100.into(); // 创建了类型为 T 的变量 a，它的初始值由 100 转换而来\n",
    "    println!(\"a is: {}\", a);\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    create_and_print(); // 有时候，编译器无法推断你想要的泛型参数\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a is: 100\n"
     ]
    }
   ],
   "source": [
    "use std::fmt::Display;\n",
    "\n",
    "fn create_and_print<T>() where T: From<i32> + Display {\n",
    "    let a: T = 100.into(); // 创建了类型为 T 的变量 a，它的初始值由 100 转换而来\n",
    "    println!(\"a is: {}\", a);\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    create_and_print::<i64>();\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 结构体中使用泛型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Point<T> {\n",
    "    x: T,\n",
    "    y: T,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let integer = Point { x: 5, y: 10 };\n",
    "    let float = Point { x: 1.0, y: 4.0 };\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里有两点需要特别的注意：\n",
    "\n",
    "- **提前声明**，跟泛型函数定义类似，首先我们在使用泛型参数之前必需要进行声明 `Point<T>`，接着就可以在结构体的字段类型中使用 `T` 来替代具体的类型\n",
    "- **x 和 y 是相同的类型**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "mismatched types",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0308] Error:\u001b[0m mismatched types",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_13:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m7 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mP\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;54m1\u001b[0m\u001b[38;5;54m.\u001b[0m\u001b[38;5;54m1\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                            \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                             \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected integer, found floating-point number",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "struct Point<T> {\n",
    "    x: T,\n",
    "    y: T,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let p = Point{x: 1, y :1.1};\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 如果想让 x 和 y 既能类型相同，又能类型不同，就需要使用不同的泛型参数：\n",
    "\n",
    "struct Point<T,U> {\n",
    "    x: T,\n",
    "    y: U,\n",
    "}\n",
    "fn main() {\n",
    "    let p = Point{x: 1, y :1.1};\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 枚举中使用泛型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enum Option<T> { // Option<T> 是一个拥有泛型 T 的枚举类型，它第一个成员是 Some(T)，存放了一个类型为 T 的值\n",
    "    Some(T),\n",
    "    None,\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enum Result<T, E> {\n",
    "    Ok(T),\n",
    "    Err(E),\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个枚举和 `Option` 一样，主要用于函数返回值，与 `Option` 用于值的存在与否不同，`Result `关注的主要是值的正确性。\n",
    "\n",
    "如果函数正常运行，则最后返回一个 `Ok(T)`，`T` 是函数具体的返回值类型，如果函数异常运行，则返回一个 `Err(E)`，`E` 是错误类型。例如打开一个文件：如果成功打开文件，则返回 `Ok(std::fs::File)`，因此 `T` 对应的是 `std::fs::File` 类型；而当打开文件时出现问题时，返回 `Err(std::io::Error)`，`E` 对应的就是 `std::io::Error` 类型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10 / 2 = 5\n",
      "Error: cannot divide by zero\n"
     ]
    }
   ],
   "source": [
    "enum Result<T, E> {\n",
    "    Ok(T),\n",
    "    Err(E),\n",
    "}\n",
    "\n",
    "fn divide(dividend: f64, divisor: f64) -> Result<f64, &'static str> {\n",
    "    if divisor == 0.0 {\n",
    "        Result::Err(\"cannot divide by zero\")\n",
    "    } else {\n",
    "        Result::Ok(dividend / divisor)\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    match divide(10.0, 2.0) {\n",
    "        Result::Ok(value) => println!(\"10 / 2 = {}\", value),\n",
    "        Result::Err(err) => println!(\"Error: {}\", err),\n",
    "    }\n",
    "\n",
    "    match divide(5.0, 0.0) {\n",
    "        Result::Ok(value) => println!(\"5 / 0 = {}\", value),\n",
    "        Result::Err(err) => println!(\"Error: {}\", err),\n",
    "    }\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> AI:\n",
    "\n",
    "在 Rust 里，`&'` 这个组合意味着“带显式生命周期的引用”。\n",
    "\n",
    "- `&`：表示引用（borrow），即不获取所有权地访问某个值。\n",
    "- `'a`（带前缀单引号的名称）：表示生命周期参数，用来描述引用可用的作用域。\n",
    "- 把两者放在一起：`&'a T` 就是“一个指向 `T` 的引用，并且这个引用在生命周期 `'a` 内有效”。\n",
    "\n",
    "具体到示例里的 `&'static str`：\n",
    "\n",
    "- `&`：字符串切片的引用。\n",
    "- `'static`：编译器内置的特殊生命周期，表示引用在整个程序运行期间始终有效。\n",
    "- `str`：被引用的字符串切片类型。\n",
    "\n",
    "因此，`&'static str` 的含义就是“一个在整个程序生命周期都有效的字符串切片引用”，常见于字符串字面量，因为它们被编译器放在只读内存里，直到程序结束都存在。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 方法中使用泛型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Point<T> {\n",
    "    x: T,\n",
    "    y: T,\n",
    "}\n",
    "\n",
    "impl<T> Point<T> {\n",
    "    fn x(&self) -> &T {\n",
    "        &self.x\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let p = Point { x: 5, y: 10 };\n",
    "\n",
    "    println!(\"p.x = {}\", p.x());\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 在该结构体的方法中定义额外的泛型参数\n",
    "\n",
    "struct Point<T, U> {\n",
    "    x: T,\n",
    "    y: U,\n",
    "}\n",
    "\n",
    "impl<T, U> Point<T, U> {\n",
    "    fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {\n",
    "        Point {\n",
    "            x: self.x,\n",
    "            y: other.y,\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let p1 = Point { x: 5, y: 10.4 };\n",
    "    let p2 = Point { x: \"Hello\", y: 'c'};\n",
    "\n",
    "    let p3 = p1.mixup(p2);\n",
    "\n",
    "    println!(\"p3.x = {}, p3.y = {}\", p3.x, p3.y);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 为具体的泛型类型实现方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于 `Point<T>` 类型，你不仅能定义基于 `T` 的方法，还能针对特定的具体类型，进行方法定义："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "impl Point<f32> {\n",
    "    fn distance_from_origin(&self) -> f32 {\n",
    "        (self.x.powi(2) + self.y.powi(2)).sqrt()\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这段代码意味着 `Point<f32>` 类型会有一个方法 `distance_from_origin`，而其他 `T` 不是 `f32` 类型的 `Point<T> `实例则没有定义此方法。这个方法计算点实例与坐标`(0.0, 0.0)` 之间的距离，并使用了只能用于浮点型的数学运算符。\n",
    "\n",
    "这样我们就能针对特定的泛型类型实现某个特定的方法，对于其它泛型类型则没有定义该方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> C++模版特化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### const 泛型（Rust 1.51 版本引入的重要特性）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "mismatched types",
     "output_type": "error",
     "traceback": [
      "  display_array(arr);",
      "\u001b[91m                ^^^\u001b[0m \u001b[94mexpected an array with a size of 3, found one with a size of 2\u001b[0m",
      "  display_array(arr);",
      "\u001b[91m  ^^^^^^^^^^^^^\u001b[0m \u001b[94marguments to this function are incorrect\u001b[0m",
      "mismatched types"
     ]
    }
   ],
   "source": [
    "// [i32; 2] 和 [i32; 3] 是不同的数组类型\n",
    "\n",
    "fn display_array(arr: [i32; 3]) {\n",
    "    println!(\"{:?}\", arr);\n",
    "}\n",
    "\n",
    "{\n",
    "  let arr: [i32; 3] = [1, 2, 3];\n",
    "  display_array(arr);\n",
    "\n",
    "  let arr: [i32; 2] = [1, 2];\n",
    "  display_array(arr);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3]\n",
      "[1, 2]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn display_array(arr: &[i32]) { // 只要使用数组切片，然后传入 arr 的不可变引用即可\n",
    "    println!(\"{:?}\", arr);\n",
    "}\n",
    "\n",
    "{\n",
    "  let arr: [i32; 3] = [1, 2, 3];\n",
    "  display_array(&arr);\n",
    "\n",
    "  let arr: [i32; 2] = [1, 2];\n",
    "  display_array(&arr);\n",
    "  }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3]\n",
      "[1, 2]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 需要对 T 加一个限制 std::fmt::Debug，该限制表明 T 可以用在 println!(\"{:?}\", arr) 中，因为 {:?} 形式的格式化输出需要 arr 实现该特征。\n",
    "\n",
    "fn display_array<T: std::fmt::Debug>(arr: &[T]) {\n",
    "    println!(\"{:?}\", arr);\n",
    "}\n",
    "\n",
    "{\n",
    "    let arr: [i32; 3] = [1, 2, 3];\n",
    "    display_array(&arr);\n",
    "\n",
    "    let arr: [i32; 2] = [1, 2];\n",
    "    display_array(&arr);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过引用，我们可以很轻松的解决处理任何类型数组的问题，但是如果在某些场景下*引用不适宜用或者干脆不能用*呢？你们知道为什么以前 Rust 的一些数组库，在使用的时候都限定长度不超过 32 吗？因为它们会为每个长度都单独实现一个函数，简直。。。毫无人性。难道没有什么办法可以解决这个问题吗？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3]\n",
      "[1, 2]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 有了 const 泛型，也就是针对值的泛型，正好可以用于处理数组长度的问题：\n",
    "\n",
    "fn display_array<T: std::fmt::Debug, const N: usize>(arr: [T; N]) {\n",
    "    println!(\"{:?}\", arr);\n",
    "}\n",
    "\n",
    "{\n",
    "    let arr: [i32; 3] = [1, 2, 3];\n",
    "    display_array(arr);\n",
    "\n",
    "    let arr: [i32; 2] = [1, 2];\n",
    "    display_array(arr);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如上所示，我们定义了一个类型为 `[T; N]` 的数组，其中 `T` 是一个基于类型的泛型参数，这个和之前讲的泛型没有区别，而重点在于 `N` 这个泛型参数，它是一个基于值的泛型参数！因为它用来替代的是数组的长度。\n",
    "\n",
    "`N` 就是 const 泛型，定义的语法是 `const N: usize`，表示 const 泛型 `N` ，它基于的值类型是 `usize`。\n",
    "\n",
    "在泛型参数之前，Rust 完全不适合复杂矩阵的运算，自从有了 const 泛型，一切即将改变。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### const 泛型表达式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 假设我们某段代码需要在内存很小的平台上工作，因此需要限制函数参数占用的内存大小，此时就可以使用 const 泛型表达式来实现：\n",
    "\n",
    "fn something<T>(val: T)\n",
    "where\n",
    "    Assert<{ core::mem::size_of::<T>() < 768 }>: IsTrue,\n",
    "    //       ^-----------------------------^ 这里是一个 const 表达式，换成其它的 const 表达式也可以\n",
    "{\n",
    "    //\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    something([0u8; 0]); // ok\n",
    "    something([0u8; 512]); // ok\n",
    "    something([0u8; 1024]); // 编译错误，数组长度是1024字节，超过了768字节的参数长度限制\n",
    "}\n",
    "\n",
    "// ---\n",
    "\n",
    "pub enum Assert<const CHECK: bool> {\n",
    "    //\n",
    "}\n",
    "\n",
    "pub trait IsTrue {\n",
    "    //\n",
    "}\n",
    "\n",
    "impl IsTrue for Assert<true> {\n",
    "    //\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### const fn\n",
    "\n",
    "`const fn`，即常量函数。`const fn` 允许我们在编译期对函数进行求值，从而实现更高效、更灵活的代码设计。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**为什么需要 const fn**\n",
    "\n",
    "通常情况下，函数是在运行时被调用和执行的。然而，在某些场景下，我们希望在编译期就计算出一些值，以提高运行时的性能或满足某些编译期的约束条件。例如，定义数组的长度、计算常量值等。\n",
    "\n",
    "有了 `const fn`，我们可以在编译期执行这些函数，从而将计算结果直接嵌入到生成的代码中。这不仅提高了运行时的性能，还使代码更加简洁和安全。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**const fn 的基本用法**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The result is: 15\n"
     ]
    }
   ],
   "source": [
    "const fn add(a: usize, b: usize) -> usize { // 要定义一个常量函数，只需要在函数声明前加上 const 关键字\n",
    "    a + b\n",
    "}\n",
    "\n",
    "const RESULT: usize = add(5, 10);\n",
    "\n",
    "println!(\"The result is: {}\", RESULT);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**const fn 的限制**\n",
    "\n",
    "虽然 `const fn` 提供了很多便利，但是由于其在编译期执行，以确保函数能在编译期被安全地求值，因此有一些限制，例如，不可将随机数生成器写成 `const fn`。\n",
    "\n",
    "无论在编译时还是运行时调用 `const fn`，它们的结果总是相同，即使多次调用也是如此。唯一的例外是，如果你在极端情况下进行复杂的浮点操作，你可能会得到（非常轻微的）不同结果。因此，不建议使 `数组长度 (arr.len())` 和 `Enum判别式` 依赖于浮点计算。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**结合 const fn 与 const 泛型**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Buffer size: 4096 bytes\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 创建一个固定大小的缓冲区结构，其中缓冲区大小由编译期计算确定：\n",
    "\n",
    "struct Buffer<const N: usize> {\n",
    "    data: [u8; N],\n",
    "}\n",
    "\n",
    "const fn compute_buffer_size(factor: usize) -> usize { // compute_buffer_size 是一个常量函数，它根据传入的 factor 计算缓冲区的大小\n",
    "    factor * 1024                                      // 缓冲区的大小在编译期就被确定下来，避免了运行时的计算开销\n",
    "}\n",
    "\n",
    "{\n",
    "    const SIZE: usize = compute_buffer_size(4);\n",
    "    let buffer = Buffer::<SIZE> {\n",
    "        data: [0; SIZE],\n",
    "    };\n",
    "    println!(\"Buffer size: {} bytes\", buffer.data.len());\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 泛型的性能\n",
    "\n",
    "- 在 Rust 中泛型是零成本的抽象，意味着你在使用泛型时，完全不用担心性能上的问题。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let integer = Some(5);\n",
    "let float = Some(5.0);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当 Rust 编译这些代码的时候，它会进行单态化。编译器会读取传递给 `Option<T>` 的值并发现有两种 `Option<T>`：一种对应 `i32` 另一种对应 `f64`。为此，它会将泛型定义 `Option<T>` 展开为 `Option_i32` 和 `Option_f64`，接着将泛型定义替换为这两个具体的定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enum Option_i32 {\n",
    "    Some(i32),\n",
    "    None,\n",
    "}\n",
    "\n",
    "enum Option_f64 {\n",
    "    Some(f64),\n",
    "    None,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let integer = Option_i32::Some(5);\n",
    "    let float = Option_f64::Some(5.0);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 验证\n",
    "\n",
    "#[inline(never)]\n",
    "fn square<T>(x: T) -> T \n",
    "where\n",
    "    T: Copy + std::ops::Mul<Output = T>,\n",
    "{\n",
    "    x * x\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let a = square(3i32);\n",
    "    let b = square(2.5f64);\n",
    "    println!(\"{a}, {b}\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! rustup toolchain install nightly  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "MONO_ITEM fn square::<f64> @@ monomorphization.7e00efe7932c339c-cgu.0[Internal]\n",
       "MONO_ITEM fn square::<i32> @@ monomorphization.7e00efe7932c339c-cgu.0[Internal]\n"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd monomorphization && cargo +nightly rustc --release -- -Zprint-mono-items 2>&1 | grep \"MONO_ITEM fn square\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 特征 Trait\n",
    "\n",
    "- https://course.rs/basic/trait/trait.html\n",
    "- https://practice-zh.course.rs/generics-traits/traits.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/generics-traits/traits.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 主题                | 关键概念                                                     | 示例/备注                                                    |\n",
    "| ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |\n",
    "| 特征定义            | 使用 `trait` 关键字声明一组共享行为，只给出方法签名，不提供实现 | `pub trait Summary { fn summarize(&self) -> String; }`       |\n",
    "| 为类型实现特征      | `impl Trait for Type`，在实现块中给出具体方法体              | `impl Summary for Post { fn summarize(&self) -> String { ... } }` |\n",
    "| 孤儿规则            | 为类型 `A` 实现特征 `T` 时，`A` 或 `T` 必须在当前作用域中定义 | 不能在本地为标准库的 `String` 实现标准库的 `Display`         |\n",
    "| 默认实现            | 在特征内提供方法默认体，实现者可选择接受或重写               | `fn summarize(&self) -> String { String::from(\"(Read more...)\") }` |\n",
    "| 特征作为函数参数    | `impl Trait` 语法糖或显式泛型+约束，实现者类型满足特征即可传入 | `pub fn notify(item: &impl Summary)` 等价 `pub fn notify<T: Summary>(item: &T)` |\n",
    "| 多重特征约束        | 使用 `+` 组合多个特征需求                                    | `pub fn notify<T: Summary + Display>(item: &T)`              |\n",
    "| `where` 子句        | 将复杂约束移出函数签名，提高可读性                           | `fn some_function<T, U>(...) -> i32 where T: Display + Clone, U: Clone + Debug` |\n",
    "| 条件实现            | 依据特征约束为类型添加方法或实现其他特征                     | `impl<T: Display + PartialOrd> Pair<T> { fn cmp_display(&self) { ... } }` |\n",
    "| `impl Trait` 返回值 | 隐藏具体返回类型，只暴露所实现的特征；要求所有分支返回同一具体类型 | `fn returns_summarizable() -> impl Summary { Weibo { ... } }` |\n",
    "| 修复 `largest` 示例 | 通过特征约束让泛型支持比较；若需拷贝再约束 `Copy`/`Clone`，或返回引用避免复制 | `fn largest<T: PartialOrd + Copy>(list: &[T]) -> T`          |\n",
    "| `derive` 派生       | 使用 `#[derive(...)]` 自动生成常见特征实现，例如 `Debug`、`Copy`、`Clone` 等 | `#[derive(Debug)] struct Point { ... }`                      |\n",
    "| 引入特征            | 使用某特征的方法前需在作用域内 `use` 该特征；常用特征已在 `std::prelude` 自动导入 | `use std::convert::TryInto;` 引入 `try_into`                 |\n",
    "| 综合示例            | 为自定义类型实现运算或格式化输出时，结合特征与约束           | `impl<T: Add<Output = T>> Add for Point<T>`、`impl Display for File { ... }` |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果我们想定义一个文件系统，那么把该系统跟底层存储解耦是很重要的。文件操作主要包含四个：`open` 、`write`、`read`、`close`，这些操作可以发生在硬盘，可以发生在内存，还可以发生在网络 IO 甚至（...我实在编不下去了，大家来帮帮我）。总之如果你要为每一种情况都单独实现一套代码，那这种实现将过于繁杂，而且也没那个必要。\n",
    "\n",
    "要解决上述问题，需要把这些行为抽象出来，就要使用 Rust 中的特征 `trait` 概念。可能你是第一次听说这个名词，但是不要怕，如果学过其他语言，那么大概率你听说过接口，没错，特征跟接口很类似。\n",
    "\n",
    "在之前的代码中，我们也多次见过特征的使用，例如 `#[derive(Debug)]`，它在我们定义的类型(`struct`)上自动派生 `Debug` 特征，接着可以使用 `println!(\"{:?}\", x)` 打印这个类型；再例如：\n",
    "\n",
    "```rust\n",
    "fn add<T: std::ops::Add<Output = T>>(a:T, b:T) -> T {\n",
    "    a + b\n",
    "}\n",
    "```\n",
    "\n",
    "通过 `std::ops::Add` 特征来限制 `T`，只有 `T` 实现了 `std::ops::Add` 才能进行合法的加法操作，毕竟不是所有的类型都能进行相加。\n",
    "\n",
    "这些都说明一个道理，特征定义了**一组可以被共享的行为，只要实现了特征，你就能使用这组行为**。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 定义特征"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "例如，我们现在有文章 `Post` 和微博 `Weibo` 两种内容载体，而我们想对相应的内容进行总结，也就是无论是文章内容，还是微博内容，都可以在某个时间点进行总结，那么总结这个行为就是共享的，因此可以用特征来定义："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 特征只定义行为看起来是什么样的，而不定义行为具体是怎么样的。因此，我们只定义特征方法的签名，而不进行实现，此时方法签名结尾是 ;，而不是一个 {}。\n",
    "\n",
    "pub trait Summary {\n",
    "    fn summarize(&self) -> String;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 为类型实现特征"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "pub trait Summary {\n",
    "    fn summarize(&self) -> String;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pub struct Post {\n",
    "    pub title: String, // 标题\n",
    "    pub author: String, // 作者\n",
    "    pub content: String, // 内容\n",
    "}\n",
    "\n",
    "impl Summary for Post { // impl Summary for Post，读作“为 Post 类型实现 Summary 特征”\n",
    "    fn summarize(&self) -> String {\n",
    "        format!(\"文章{}, 作者是{}\", self.title, self.author)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "pub struct Weibo {\n",
    "    pub username: String,\n",
    "    pub content: String\n",
    "}\n",
    "\n",
    "impl Summary for Weibo {\n",
    "    fn summarize(&self) -> String {\n",
    "        format!(\"{}发表了微博{}\", self.username, self.content)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "文章Rust语言简介, 作者是Sunface\n",
      "sunface发表了微博好像微博没Tweet好用\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let post = Post{title: \"Rust语言简介\".to_string(),author: \"Sunface\".to_string(), content: \"Rust棒极了!\".to_string()};\n",
    "    let weibo = Weibo{username: \"sunface\".to_string(),content: \"好像微博没Tweet好用\".to_string()};\n",
    "\n",
    "    println!(\"{}\",post.summarize());\n",
    "    println!(\"{}\",weibo.summarize());\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**特征定义与实现的位置(孤儿规则)**\n",
    "\n",
    "- 孤儿规则规定：为类型实现特征时，类型或特征至少一方必须在当前作用域中定义，否则 Rust 不允许实现，以防互相污染。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**默认实现**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 你可以在特征中定义具有默认实现的方法，这样其它类型无需再实现该方法，或者也可以选择重写该方法：\n",
    "\n",
    "pub trait Summary {\n",
    "    fn summarize(&self) -> String {\n",
    "        String::from(\"(Read more...)\")\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "pub struct Post {\n",
    "    pub title: String, // 标题\n",
    "    pub author: String, // 作者\n",
    "    pub content: String, // 内容\n",
    "}\n",
    "\n",
    "impl Summary for Post {}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "pub struct Weibo {\n",
    "    pub username: String,\n",
    "    pub content: String\n",
    "}\n",
    "\n",
    "impl Summary for Weibo {\n",
    "    fn summarize(&self) -> String {\n",
    "        format!(\"{}发表了微博{}\", self.username, self.content)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(Read more...)\n",
      "sunface发表了微博好像微博没Tweet好用\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let post = Post{title: \"Rust语言简介\".to_string(),author: \"Sunface\".to_string(), content: \"Rust棒极了!\".to_string()};\n",
    "    let weibo = Weibo{username: \"sunface\".to_string(),content: \"好像微博没Tweet好用\".to_string()};\n",
    "\n",
    "    println!(\"{}\",post.summarize());\n",
    "    println!(\"{}\",weibo.summarize());\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用特征作为函数参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Breaking news! (Read more...)\n",
      "Breaking news! sunface发表了微博好像微博没Tweet好用\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pub fn notify(item: &impl Summary) { // 实现了Summary特征 的 item 参数。\n",
    "    println!(\"Breaking news! {}\", item.summarize());\n",
    "}\n",
    "\n",
    "{\n",
    "    let post = Post{title: \"Rust语言简介\".to_string(),author: \"Sunface\".to_string(), content: \"Rust棒极了!\".to_string()};\n",
    "    notify(&post);\n",
    "\n",
    "    let weibo = Weibo{username: \"sunface\".to_string(),content: \"好像微博没Tweet好用\".to_string()};\n",
    "    notify(&weibo);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "the trait bound `String: Summary` is not satisfied",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m the trait bound `String: Summary` is not satisfied",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_33:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;100mn\u001b[0m\u001b[38;5;100mo\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100mf\u001b[0m\u001b[38;5;100my\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;54m\"\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54m\"\u001b[0m\u001b[38;5;54m.\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m    \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m required by a bound introduced by this call",
      " \u001b[38;5;240m  │\u001b[0m                  \u001b[38;5;54m│\u001b[0m           ",
      " \u001b[38;5;240m  │\u001b[0m                  \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m the trait `Summary` is not implemented for `String`",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;115mNote\u001b[0m: required by this bound in `notify`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "notify(&\"hello\".to_string());"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 特征约束(trait bound)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "虽然 `impl Trait` 这种语法非常好理解，但是实际上它只是一个语法糖："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 真正的完整书写形式如下所述，形如 T: Summary 被称为特征约束\n",
    "\n",
    "pub fn notify<T: Summary>(item: &T) {\n",
    "    println!(\"Breaking news! {}\", item.summarize());\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在简单的场景下 `impl Trait` 这种语法糖就足够使用，但是对于复杂的场景，特征约束可以让我们拥有更大的灵活性和语法表现能力，例如一个函数接受两个 `impl Summary` 的参数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pub fn notify(item1: &impl Summary, item2: &impl Summary) {}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果函数两个参数是不同的类型，那么上面的方法很好，只要这两个类型都实现了 `Summary` 特征即可。但是如果我们想要强制函数的两个参数是同一类型呢？上面的语法就无法做到这种限制，此时我们只能使特征约束来实现："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pub fn notify<T: Summary>(item1: &T, item2: &T) {} // 泛型类型 `T` 说明了 `item1` 和 `item2` 必须拥有同样的类型，同时 `T: Summary` 说明了 `T` 必须实现 `Summary` 特征。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 多重约束"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 例如除了让参数实现 Summary 特征外，还可以让参数实现 Display 特征以控制它的格式化输出\n",
    "\n",
    "pub fn notify(item: &(impl Summary + Display)) {}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 使用特征约束的形式\n",
    "\n",
    "pub fn notify<T: Summary + Display>(item: &T) {}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Where 约束"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当特征约束变得很多时，函数的签名将变得很复杂："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 {}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 通过 where\n",
    "\n",
    "fn some_function<T, U>(t: &T, u: &U) -> i32\n",
    "    where T: Display + Clone,\n",
    "          U: Clone + Debug\n",
    "{}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用特征约束有条件地实现方法或特征"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在指定类型 + 指定特征的条件下去实现方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The largest member is y = 10\n",
      "The largest member is y = banana\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::fmt::Display;\n",
    "\n",
    "struct Pair<T> {\n",
    "    x: T,\n",
    "    y: T,\n",
    "}\n",
    "\n",
    "impl<T> Pair<T> {\n",
    "    fn new(x: T, y: T) -> Self {\n",
    "        Self {\n",
    "            x,\n",
    "            y,\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "impl<T: Display + PartialOrd> Pair<T> { // 只有 T 同时实现了 Display + PartialOrd 的 Pair<T> 才可以拥有此方法\n",
    "    fn cmp_display(&self) {\n",
    "        if self.x >= self.y {\n",
    "            println!(\"The largest member is x = {}\", self.x);\n",
    "        } else {\n",
    "            println!(\"The largest member is y = {}\", self.y);\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let pair = Pair::new(5, 10);\n",
    "    pair.cmp_display();\n",
    "\n",
    "    let pair = Pair::new(\"apple\", \"banana\");\n",
    "    pair.cmp_display();\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "s1 = 42\n",
      "s2 = Point(3, 4)\n"
     ]
    }
   ],
   "source": [
    "// 有条件地实现特征: 标准库为任何实现了 Display 特征的类型实现了 ToString 特征：\n",
    "\n",
    "use std::fmt::Display;\n",
    "\n",
    "{\n",
    "    // i32 实现了 Display，因此自动拥有 ToString\n",
    "    let n: i32 = 42;\n",
    "    let s1 = n.to_string();\n",
    "    println!(\"s1 = {}\", s1);\n",
    "\n",
    "    // 自定义类型手动实现 Display 后，也自动拥有 ToString\n",
    "    let p = Point { x: 3, y: 4 };\n",
    "    let s2 = p.to_string();\n",
    "    println!(\"s2 = {}\", s2);\n",
    "}\n",
    "\n",
    "struct Point {\n",
    "    x: i32,\n",
    "    y: i32,\n",
    "}\n",
    "\n",
    "impl Display for Point {\n",
    "    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n",
    "        write!(f, \"Point({}, {})\", self.x, self.y)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 可以将整型转换为对应的 String 值，因为整型实现了 Display\n",
    "\n",
    "let s = 3.to_string();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数返回中的 impl Trait"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`impl Trait` 作为函数返回类型能隐藏具体类型、只暴露其实现的特征（适合真实类型复杂的情况），但要求所有返回路径产生同一具体类型，否则需改用特征对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sunface发表了微博m1 max太厉害了，电脑再也不会卡\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn returns_summarizable() -> impl Summary { \n",
    "    Weibo {\n",
    "        username: String::from(\"sunface\"),\n",
    "        content: String::from(\n",
    "            \"m1 max太厉害了，电脑再也不会卡\",\n",
    "        )\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let weibo = returns_summarizable();\n",
    "    println!(\"{}\", weibo.summarize());\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "返回的真实类型非常复杂"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "makes\n",
      "trait-based\n",
      "generics\n",
      "ergonomic\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 返回一个实现 Iterator 的匿名类型（map + filter 的链式组合）：\n",
    "fn long_words<'a>(text: &'a str, min_len: usize) -> impl Iterator<Item = &'a str> {\n",
    "    text.split_whitespace()\n",
    "        .filter(move |word| word.len() >= min_len)\n",
    "        .map(|word| word.trim_matches(|c: char| !c.is_alphanumeric()))\n",
    "}\n",
    "\n",
    "// 返回一个实现 Fn(i32) -> i32 的闭包类型：\n",
    "fn make_adder(delta: i32) -> impl Fn(i32) -> i32 {\n",
    "    move |x| x + delta\n",
    "}\n",
    "\n",
    "#[test]\n",
    "fn test_make_adder() {\n",
    "    let add_ten = make_adder(10);\n",
    "    assert_eq!(add_ten(5), 15); // 调用者只知道得到某个实现 Fn 的“函数”\n",
    "}\n",
    "\n",
    "for word in long_words(\"Rust makes trait-based generics ergonomic!\", 5) {\n",
    "    println!(\"{word}\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 但是这种返回值方式有一个很大的限制：只能有一个具体的类型\n",
    "// 代码无法通过编译\n",
    "\n",
    "fn returns_summarizable(switch: bool) -> impl Summary {\n",
    "    if switch {\n",
    "        Post {\n",
    "            title: String::from(\n",
    "                \"Penguins win the Stanley Cup Championship!\",\n",
    "            ),\n",
    "            author: String::from(\"Iceburgh\"),\n",
    "            content: String::from(\n",
    "                \"The Pittsburgh Penguins once again are the best \\\n",
    "                 hockey team in the NHL.\",\n",
    "            ),\n",
    "        }\n",
    "    } else {\n",
    "        Weibo {\n",
    "            username: String::from(\"horse_ebooks\"),\n",
    "            content: String::from(\n",
    "                \"of course, as you probably already know, people\",\n",
    "            ),\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "因为 `Weibo` 实现了 `Summary`，因此这里可以用它来作为返回值。要注意的是，虽然我们知道这里是一个 `Weibo` 类型，但是对于 `returns_summarizable` 的调用者而言，他只知道返回了一个实现了 `Summary` 特征的对象，但是并不知道返回了一个 `Weibo` 类型。\n",
    "\n",
    "如果想要实现返回不同的类型，需要使用下一章节中的[特征对象](https://course.rs/basic/trait/trait-object.html)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 修复上一节中的 largest 函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "binary operation `>` cannot be applied to type `T`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0369] Error:\u001b[0m binary operation `>` cannot be applied to type `T`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_2:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m<\u001b[0m\u001b[38;5;249mT\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249m[\u001b[0m\u001b[38;5;249mT\u001b[0m\u001b[38;5;249m]\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mT\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;37m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m help: consider restricting type parameter `T` with trait `PartialOrd`: `: std::cmp::PartialOrd`",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100ml\u001b[0m\u001b[38;5;100ma\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100mg\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m \u001b[38;5;68m┬\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m              \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m T",
      " \u001b[38;5;240m  │\u001b[0m                 \u001b[38;5;68m│\u001b[0m    \u001b[38;5;100m│\u001b[0m     ",
      " \u001b[38;5;240m  │\u001b[0m                 \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m error: binary operation `>` cannot be applied to type `T`",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;100m│\u001b[0m     ",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m T",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn largest<T>(list: &[T]) -> T {\n",
    "    let mut largest = list[0];\n",
    "\n",
    "    for &item in list.iter() {\n",
    "        if item > largest {\n",
    "            largest = item;\n",
    "        }\n",
    "    }\n",
    "\n",
    "    largest\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 `largest` 函数体中我们想要使用大于运算符（`>`）比较两个 `T` 类型的值。这个运算符是标准库中特征 `std::cmp::PartialOrd` 的一个默认方法。所以需要在 `T` 的特征约束中指定 `PartialOrd`，这样 `largest` 函数可以用于内部元素类型可比较大小的数组切片。\n",
    "\n",
    "由于 `PartialOrd` 位于 `prelude` 中所以并不需要通过 `std::cmp` 手动将其引入作用域。所以可以将 `largest` 的签名修改为如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot move out of type `[T]`, a non-copy slice",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0508] Error:\u001b[0m cannot move out of type `[T]`, a non-copy slice",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_2:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m[\u001b[0m\u001b[38;5;54m0\u001b[0m\u001b[38;5;54m]\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;68m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider borrowing here: `&`",
      " \u001b[38;5;240m  │\u001b[0m                          \u001b[38;5;54m│\u001b[0m     ",
      " \u001b[38;5;240m  │\u001b[0m                          \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m cannot move out of here",
      " \u001b[38;5;240m  │\u001b[0m                          \u001b[38;5;100m│\u001b[0m     ",
      " \u001b[38;5;240m  │\u001b[0m                          \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m move occurs because `list[_]` has type `T`, which does not implement the `Copy` trait",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "cannot move out of a shared reference",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0507] Error:\u001b[0m cannot move out of a shared reference",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_2:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;37m&\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68ml\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68m.\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68mr\u001b[0m\u001b[38;5;68m(\u001b[0m\u001b[38;5;68m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;37m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m    \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m help: consider removing the borrow: ``",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;54m│\u001b[0m          \u001b[38;5;68m│\u001b[0m       ",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m data moved here",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;100m│\u001b[0m          \u001b[38;5;68m│\u001b[0m       ",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m move occurs because `item` has type `T`, which does not implement the `Copy` trait",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;68m│\u001b[0m       ",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m error: cannot move out of a shared reference",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn largest<T: PartialOrd>(list: &[T]) -> T {\n",
    "    let mut largest = list[0];\n",
    "\n",
    "    for &item in list.iter() {\n",
    "        if item > largest {\n",
    "            largest = item;\n",
    "        }\n",
    "    }\n",
    "\n",
    "    largest\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "错误的核心是 `cannot move out of type [T], a non-copy slice`，原因是 `T` 没有[实现 `Copy` 特性](https://course.rs/basic/ownership/ownership.html#拷贝浅拷贝)，因此我们只能把所有权进行转移，毕竟只有 `i32` 等基础类型才实现了 `Copy` 特性，可以存储在栈上，而 `T` 可以指代任何类型（严格来说是实现了 `PartialOrd` 特征的所有类型）。\n",
    "\n",
    "因此，为了让 `T` 拥有 `Copy` 特性，我们可以增加特征约束："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {\n",
    "    let mut largest = list[0];\n",
    "\n",
    "    for &item in list.iter() {\n",
    "        if item > largest {\n",
    "            largest = item;\n",
    "        }\n",
    "    }\n",
    "\n",
    "    largest\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The largest number is 100\n",
      "The largest char is y\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let number_list = vec![34, 50, 25, 100, 65];\n",
    "\n",
    "    let result = largest(&number_list);\n",
    "    println!(\"The largest number is {}\", result);\n",
    "\n",
    "    let char_list = vec!['y', 'm', 'a', 'q'];\n",
    "\n",
    "    let result = largest(&char_list);\n",
    "    println!(\"The largest char is {}\", result);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果并不希望限制 `largest` 函数只能用于实现了 `Copy` 特征的类型，我们可以在 `T` 的特征约束中指定 [`Clone` 特征](https://course.rs/basic/ownership/ownership.html#克隆深拷贝) 而不是 `Copy` 特征。并克隆 `list` 中的每一个值使得 `largest` 函数拥有其所有权。使用 `clone` 函数意味着对于类似 `String` 这样拥有堆上数据的类型，会潜在地分配更多堆上空间，而堆分配在涉及大量数据时可能会相当缓慢。\n",
    "\n",
    "另一种 `largest` 的实现方式是返回在 `list` 中 `T` 值的引用。如果我们将函数返回值从 `T` 改为 `&T` 并改变函数体使其能够返回一个引用，我们将不需要任何 `Clone` 或 `Copy` 的特征约束而且也不会有任何的堆分配。尝试自己实现这种替代解决方式吧！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "/// 返回切片中拥有最大值的元素引用。\n",
    "/// \n",
    "/// 使用 `&T` 而不是直接返回 `T`，可以避免需要 `Copy`/`Clone`\n",
    "/// 限制，也不会产生拷贝或堆分配。\n",
    "fn largest<T: PartialOrd>(list: &[T]) -> &T {\n",
    "    // 确认输入切片非空；如果为空则 panic。\n",
    "    assert!(\n",
    "        !list.is_empty(),\n",
    "        \"largest() requires a non-empty slice\"\n",
    "    );\n",
    "\n",
    "    // 将当前“最大值”初始化为第一个元素的引用。\n",
    "    // 注意：这里是引用，后续比较也全程使用引用，避免拷贝。\n",
    "    let mut largest = &list[0];\n",
    "\n",
    "    // 遍历剩余元素。切片 [1..] 可能为空，但 `for` 会自动处理。\n",
    "    for item in &list[1..] { // `1..`: `从 1 开始直到结尾`\n",
    "        // 使用 PartialOrd 提供的 `>` 运算符在引用层面比较。\n",
    "        // `item` 和 `largest` 都是 `&T`，Rust 会自动解引用以比较其值。\n",
    "        if item > largest {\n",
    "            // 若发现更大的元素，则更新 `largest` 的引用。\n",
    "            largest = item;\n",
    "        }\n",
    "    }\n",
    "\n",
    "    // 返回指向最大元素的引用。\n",
    "    largest\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The largest number is 100\n",
      "The largest char is y\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let number_list = vec![34, 50, 25, 100, 65];\n",
    "\n",
    "    let result = largest(&number_list);\n",
    "    println!(\"The largest number is {}\", result);\n",
    "\n",
    "    let char_list = vec!['y', 'm', 'a', 'q'];\n",
    "\n",
    "    let result = largest(&char_list);\n",
    "    println!(\"The largest char is {}\", result);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> AI:\n",
    "\n",
    "`&list[1..]` 是在对切片做二级取引用：\n",
    "- `list[1..]` 本身已经返回一个指向原切片后半段的子切片 `&[T]`（起始下标为 1）；\n",
    "- 在它前面再加一个 `&`，得到的类型是 `&&[T]`。Rust 在 `for` 循环中会自动解引用，一般情况下不会出错，但这个额外的 `&` 是冗余的。\n",
    "\n",
    "更直接、也更常见的写法有两种：\n",
    "\n",
    "```rust\n",
    "for item in list[1..].iter() { /* … */ }   // 显式调用迭代器\n",
    "// 或\n",
    "for item in &list[1..] { /* … */ }         // 使用子切片本身的 IntoIterator\n",
    "```\n",
    "\n",
    "后一种写法中编译器会把 `&list[1..]` 自动简化为 `list[1..]`（类型是 `&[T]`），再通过 `IntoIterator` 迭代出 `&T`。因此如果看到 `&list[1..]`，可以把它理解为“对下标 1 起的那段子切片进行迭代”，只不过多写了一个无害但没必要的取引用符号。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 通过 derive 派生特征"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在本书中，形如 `#[derive(Debug)]` 的代码已经出现了很多次，这种是一种特征派生语法，被 `derive` 标记的对象会自动实现对应的默认特征代码，继承相应的功能。\n",
    "\n",
    "例如 `Debug` 特征，它有一套自动实现的默认代码，当你给一个结构体标记后，就可以使用 `println!(\"{:?}\", s)` 的形式打印该结构体的对象。\n",
    "\n",
    "再如 `Copy` 特征，它也有一套自动实现的默认代码，当标记到一个类型上时，可以让这个类型自动实现 `Copy` 特征，进而可以调用 `copy` 方法，进行自我复制。\n",
    "\n",
    "总之，`derive` 派生出来的是 Rust 默认给我们提供的特征，在开发过程中极大的简化了自己手动实现相应特征的需求，当然，如果你有特殊的需求，还可以自己手动重写该实现。\n",
    "\n",
    "详细的 `derive` 列表参见[附录-派生特征](https://course.rs/appendix/derive.html)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 调用方法需要引入特征"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在一些场景中，使用 `as` 关键字做类型转换会有比较大的限制，因为你想要在类型转换上拥有完全的控制，例如处理转换错误，那么你将需要 `TryInto`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ten is less than one hundred.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::convert::TryInto;\n",
    "\n",
    "{\n",
    "  let a: i32 = 10;\n",
    "  let b: u16 = 100;\n",
    "\n",
    "  let b_ = b.try_into().unwrap();\n",
    "\n",
    "  if a < b_ {\n",
    "    println!(\"Ten is less than one hundred.\");\n",
    "  }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面代码中引入了 `std::convert::TryInto` 特征，但是却没有使用它，可能有些同学会为此困惑，主要原因在于**如果你要使用一个特征的方法，那么你需要将该特征引入当前的作用域中**，我们在上面用到了 `try_into` 方法，因此需要引入对应的特征。\n",
    "\n",
    "但是 Rust 又提供了一个非常便利的办法，即把最常用的标准库中的特征通过 [`std::prelude`](https://course.rs/appendix/prelude.html) 模块提前引入到当前作用域中，其中包括了 `std::convert::TryInto`，你可以尝试删除第一行的代码 `use ...`，看看是否会报错。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 几个综合例子"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**为自定义类型实现 + 操作**\n",
    "\n",
    "在 Rust 中除了数值类型的加法，`String` 也可以做[加法](https://course.rs/basic/compound-type/string-slice.html#操作字符串)，因为 Rust 为该类型实现了 `std::ops::Add` 特征，同理，如果我们为自定义类型实现了该特征，那就可以自己实现 `Point1 + Point2` 的操作:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Point { x: 3.1999998, y: 3.1999998 }\n",
      "Point { x: 3, y: 3 }\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::ops::Add;\n",
    "\n",
    "// 为Point结构体派生Debug特征，用于格式化输出\n",
    "// 约束 `T: Add<T, Output = T>` 表示：\n",
    "/// - 可以对两个 `T` 类型的值执行加法；\n",
    "/// - 加法结果仍然是 `T` 类型；\n",
    "#[derive(Debug)]\n",
    "struct Point<T: Add<T, Output = T>> { // 限制类型T必须实现了Add特征，否则无法进行+操作。\n",
    "    x: T,\n",
    "    y: T,\n",
    "}\n",
    "\n",
    "impl<T: Add<T, Output = T>> Add for Point<T> {\n",
    "    type Output = Point<T>;\n",
    "\n",
    "    fn add(self, p: Point<T>) -> Point<T> {\n",
    "        Point{\n",
    "            x: self.x + p.x,\n",
    "            y: self.y + p.y,\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "fn add<T: Add<T, Output=T>>(a:T, b:T) -> T {\n",
    "    a + b\n",
    "}\n",
    "\n",
    "{\n",
    "    let p1 = Point{x: 1.1f32, y: 1.1f32};\n",
    "    let p2 = Point{x: 2.1f32, y: 2.1f32};\n",
    "    println!(\"{:?}\", add(p1, p2));\n",
    "\n",
    "    let p3 = Point{x: 1i32, y: 1i32};\n",
    "    let p4 = Point{x: 2i32, y: 2i32};\n",
    "    println!(\"{:?}\", add(p3, p4));\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "p1 + p2 = Point { x: 3.1999998, y: 3.1999998 }\n",
      "add(p3, p4) = Point { x: 3, y: 3 }\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::ops::Add;\n",
    "\n",
    "/// 二维坐标点。\n",
    "///\n",
    "/// 约束 `T: Add<Output = T> + Copy` 的原因：\n",
    "///\n",
    "/// - `Add<Output = T>`：保证我们能对同类型的两个 `T` 做加法，并且结果还是 `T`；\n",
    "/// - `Copy`：让 `Point<T>` 也可以 `Copy`，这样我们在用 `p1 + p2` 时不会消耗原值，便于重复使用。\n",
    "#[derive(Debug, Clone, Copy, PartialEq)]\n",
    "struct Point<T>\n",
    "where\n",
    "    T: Add<Output = T> + Copy,\n",
    "{\n",
    "    /// x 坐标\n",
    "    x: T,\n",
    "    /// y 坐标\n",
    "    y: T,\n",
    "}\n",
    "\n",
    "/// 为 `Point<T>` 实现 `+` 运算符：\n",
    "///\n",
    "/// - 输入：`self` 与 `rhs`（另一个 `Point<T>`）\n",
    "/// - 输出：新的 `Point<T>`\n",
    "///\n",
    "/// 通过 trait 的方式重载 `+`，语义清晰、类型安全。\n",
    "impl<T> Add for Point<T>\n",
    "where\n",
    "    T: Add<Output = T> + Copy,\n",
    "{\n",
    "    type Output = Self;\n",
    "\n",
    "    fn add(self, rhs: Self) -> Self::Output {\n",
    "        Self {\n",
    "            x: self.x + rhs.x,\n",
    "            y: self.y + rhs.y,\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "/// 通用的“加法函数”，演示如何复用运算符重载：\n",
    "///\n",
    "/// - 只要 `T` 支持 `+`，就可以调用此函数。\n",
    "fn add<T>(a: T, b: T) -> T\n",
    "where\n",
    "    T: Add<Output = T>,\n",
    "{\n",
    "    a + b\n",
    "}\n",
    "\n",
    "{\n",
    "    let p1 = Point { x: 1.1_f32, y: 1.1_f32 };\n",
    "    let p2 = Point { x: 2.1_f32, y: 2.1_f32 };\n",
    "\n",
    "    // 直接使用 `+` 运算符（来源于我们上面实现的 Add）\n",
    "    let sum_f32 = p1 + p2;\n",
    "    println!(\"p1 + p2 = {:?}\", sum_f32);\n",
    "\n",
    "    let p3 = Point { x: 1_i32, y: 1_i32 };\n",
    "    let p4 = Point { x: 2_i32, y: 2_i32 };\n",
    "\n",
    "    // 通过通用函数 add()，最终仍然调用了 `+`\n",
    "    let sum_i32 = add(p3, p4);\n",
    "    println!(\"add(p3, p4) = {:?}\", sum_i32);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**自定义类型的打印输出**\n",
    "\n",
    "在开发过程中，往往只要使用 #[derive(Debug)] 对我们的自定义类型进行标注，即可实现打印输出的功能："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Point { x: 3, y: 3 }\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#[derive(Debug)]\n",
    "struct Point{\n",
    "    x: i32,\n",
    "    y: i32\n",
    "}\n",
    "\n",
    "{\n",
    "    let p = Point{x:3,y:3};\n",
    "    println!(\"{:?}\",p);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "但是在实际项目中，往往需要对我们的自定义类型进行自定义的格式化输出，以让用户更好的阅读理解我们的类型，此时就要为自定义类型实现 `std::fmt::Display` 特征："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "File { name: \"f6.txt\", data: [], state: Closed }\n",
      "<f6.txt (CLOSED)>\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#![allow(dead_code)] // 允许存在未使用的代码（例如某些调试函数），避免编译器发出警告。\n",
    "\n",
    "use std::fmt;\n",
    "use std::fmt::Display;\n",
    "\n",
    "/// 表示文件的状态：已打开或已关闭。\n",
    "#[derive(Debug, PartialEq)] // 当你为某个类型实现（或派生）PartialEq 后，就可以使用 == 与 != 来比较该类型的两个值是否相等\n",
    "enum FileState {\n",
    "    Open,\n",
    "    Closed,\n",
    "}\n",
    "\n",
    "/// 文件结构体，包含文件名、数据缓冲区以及当前状态。\n",
    "#[derive(Debug)]\n",
    "struct File {\n",
    "    name: String,\n",
    "    data: Vec<u8>,\n",
    "    state: FileState,\n",
    "}\n",
    "\n",
    "/// 为 FileState 实现 Display，用于 `{}` 格式化输出。\n",
    "impl Display for FileState {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        match *self {\n",
    "            FileState::Open => write!(f, \"OPEN\"),\n",
    "            FileState::Closed => write!(f, \"CLOSED\"),\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "/// 为 File 实现 Display，让我们可以通过 `{}` 打印友好的文件信息。\n",
    "impl Display for File {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        // 直接复用 FileState 的 Display 实现来打印状态。\n",
    "        write!(f, \"<{} ({})>\", self.name, self.state)\n",
    "    }\n",
    "}\n",
    "\n",
    "impl File {\n",
    "    /// 创建一个新的 File，初始状态为 Closed，数据为空。\n",
    "    fn new(name: &str) -> File {\n",
    "        File {\n",
    "            name: String::from(name),\n",
    "            data: Vec::new(),\n",
    "            state: FileState::Closed,\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    // 创建一个名为 f6.txt 的文件实例，默认关闭状态。\n",
    "    let f6 = File::new(\"f6.txt\");\n",
    "\n",
    "    // `{:?}` 使用 Debug 输出，显示结构体的详细字段信息。\n",
    "    println!(\"{:?}\", f6);\n",
    "\n",
    "    // `{}` 使用我们自定义的 Display 输出，显示更简洁友好的信息。\n",
    "    println!(\"{}\", f6);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## * 特征对象\n",
    "\n",
    "- https://course.rs/basic/trait/trait-object.html\n",
    "- https://practice-zh.course.rs/generics-traits/trait-object.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/generics-traits/trait-object.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 主题                    | 核心概念                                    | 关键点                                                       | 示例/备注                                                    |\n",
    "| ----------------------- | ------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |\n",
    "| 单一返回类型限制        | `-> impl Trait` 只能返回同一具体类型        | `impl Summary` 版本无法在 `Post` 与 `Weibo` 间切换           | 需要改用特征对象（如 `Box<dyn Summary>`）或枚举              |\n",
    "| 动态混合对象集合        | 无法事先枚举的多类型 UI 组件                | 以特征抽象通用行为（如 `Draw`）                              | `Vec<Box<dyn Draw>>` 可同时存 `Button`/`SelectBox`           |\n",
    "| 特征对象 (Trait Object) | 将“实现了某特征的任意类型”作为统一类型处理  | 使用 `dyn Trait`，通常搭配 `&dyn Trait`/`Box<dyn Trait>`     | `Box::new(Button)` → `Box<dyn Draw>`，运行期通过 vtable 调度 |\n",
    "| 动态分发                | 调用特征对象方法需运行期查表                | 带来灵活性但失去静态派发优化，如内联                         | 对比 `Vec<T>` + 泛型（静态派发，性能更好）                   |\n",
    "| UI Screen 示例          | `Screen { components: Vec<Box<dyn Draw>> }` | `run()` 遍历组件并调用 `draw()`                              | 任何实现 `Draw` 的类型都可加入                               |\n",
    "| 鸭子类型对比            | “看起来像鸭子”即视为鸭子                    | Rust 编译期检查确保实现特征，避免运行期错误                  | 未实现特征的类型（如 `String`）无法加入集合                  |\n",
    "| 对象安全                | 仅对象安全特征才能做特征对象                | 方法返回值不能是 `Self`，方法不得含泛型参数                  | `Clone::clone(&self) -> Self` 非对象安全，不能 `Box<dyn Clone>` |\n",
    "| `self` / `Self` 区分    | `self` 指实例，`Self` 指实现类型别名        | 对象安全要求禁止返回 `Self`                                  | `fn draw(&self) -> Self` 破坏对象安全                        |\n",
    "| `dyn` 语法注意          | `dyn` 仅在类型位置出现                      | 不能写 `fn draw(x: dyn Draw)`，必须 `&dyn Draw` 或 `Box<dyn Draw>` | 引用/智能指针大小固定，能持有未知大小的实现                  |\n",
    "\n",
    "进一步提示：\n",
    "\n",
    "- 选用特征对象（动态分发）还是泛型（静态分发）取决于是否需要在同一容器中混合多类型实例，以及对性能的要求。\n",
    "- `Box<T>` 在创建特征对象时会移动数据到堆上；若不需要所有权可使用 `&dyn Trait`。\n",
    "- 牢记对象安全规则，必要时可改写接口（如返回 `Box<dyn Trait>` 或关联类型）以满足对象安全。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在上一节中有一段代码无法通过编译："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 但是这种返回值方式有一个很大的限制：只能有一个具体的类型\n",
    "// 代码无法通过编译\n",
    "\n",
    "fn returns_summarizable(switch: bool) -> impl Summary {\n",
    "    if switch {\n",
    "        Post {\n",
    "            title: String::from(\n",
    "                \"Penguins win the Stanley Cup Championship!\",\n",
    "            ),\n",
    "            author: String::from(\"Iceburgh\"),\n",
    "            content: String::from(\n",
    "                \"The Pittsburgh Penguins once again are the best \\\n",
    "                 hockey team in the NHL.\",\n",
    "            ),\n",
    "        }\n",
    "    } else {\n",
    "        Weibo {\n",
    "            username: String::from(\"horse_ebooks\"),\n",
    "            content: String::from(\n",
    "                \"of course, as you probably already know, people\",\n",
    "            ),\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "其中 `Post` 和 `Weibo` 都实现了 `Summary` 特征，因此上面的函数试图通过返回 `impl Summary` 来返回这两个类型，但是编译器却无情地报错了，原因是 `impl Trait` 的返回值类型并不支持多种不同的类型返回，那如果我们想返回多种类型，该怎么办？\n",
    "\n",
    "再来考虑一个问题：现在在做一款游戏，需要将多个对象渲染在屏幕上，这些对象属于不同的类型，存储在列表中，渲染的时候，需要循环该列表并顺序渲染每个对象，在 Rust 中该怎么实现？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Button\n",
      "SelectBox\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 利用枚举：\n",
    "\n",
    "#[derive(Debug)]\n",
    "enum UiObject {\n",
    "    Button,\n",
    "    SelectBox,\n",
    "}\n",
    "\n",
    "fn draw(o: UiObject) {\n",
    "    println!(\"{:?}\",o);\n",
    "}\n",
    "\n",
    "{\n",
    "    let objects = [\n",
    "        UiObject::Button,\n",
    "        UiObject::SelectBox\n",
    "    ];\n",
    "\n",
    "    for o in objects {\n",
    "        draw(o)\n",
    "    }\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Bingo，这个确实是一个办法，但是问题来了，如果你的对象集合并不能事先明确地知道呢？或者别人想要实现一个 UI 组件呢？此时枚举中的类型是有些缺少的，是不是还要修改你的代码增加一个枚举成员？\n",
    "\n",
    "总之，在编写这个 UI 库时，我们无法知道所有的 UI 对象类型，只知道的是：\n",
    "\n",
    "- UI 对象的类型不同\n",
    "- 需要一个统一的类型来处理这些对象，无论是作为函数参数还是作为列表中的一员\n",
    "- 需要对每一个对象调用 `draw` 方法\n",
    "\n",
    "在拥有继承的语言中，可以定义一个名为 `Component` 的类，该类上有一个 `draw` 方法。其他的类比如 `Button`、`Image` 和 `SelectBox` 会从 `Component` 派生并因此继承 `draw` 方法。它们各自都可以覆盖 `draw` 方法来定义自己的行为，但是框架会把所有这些类型当作是 `Component` 的实例，并在其上调用 `draw`。不过 Rust 并没有继承，我们得另寻出路。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> AI:\n",
    "\n",
    "Rust 的 `-> impl Summary` 只能返回单一具体类型，因此无法在同一函数中既返回 `Post` 又返回 `Weibo`。遇到需要“多类型同返回值”或“容器内混存不同类型”的场景，可使用 **特征对象**（例如 `Box<dyn Summary>` 或 `Vec<Box<dyn Draw>>`）。它们允许将所有实现了某 trait 的类型以统一接口处理，并在运行时通过 vtable 动态分发。\n",
    "\n",
    "- 枚举只适用于类型集合固定的情况。\n",
    "- 特征对象适合“类型未知但行为相同”：\n",
    "  - 统一接口：`trait Draw { fn draw(&self); }`\n",
    "  - 存储：`Vec<Box<dyn Draw>>`\n",
    "  - 使用：`component.draw();`\n",
    "- 注意对象安全约束：方法不能返回 `Self`，也不能包含泛型参数。\n",
    "\n",
    "这就是在无继承的 Rust 中模拟“鸭子类型”的方式。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### * 特征对象定义\n",
    "\n",
    "> - **特征对象** ≈ “指向实现某个接口的实例的引用”（类比 Java/C# 接口引用或 C++ 虚基类指针）。\n",
    "> - 它让 Rust 在保持类型安全的同时，具备动态多态与“鸭子类型”风格的编程体验。\n",
    "> - 选择 `Box<dyn Trait>` 还是泛型，应依据运行时灵活性与性能需求权衡。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当需要在**运行期**统一处理“实现同一组行为但类型各异”的值时，Rust 提供了 **特征对象**（`dyn Trait`）。它们通过 vtable（虚函数表）实现动态分发，是弥补 Rust 无继承机制时的重要工具。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 定义统一行为：`Draw`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 定义统一行为：`Draw`\n",
    "\n",
    "pub trait Draw {\n",
    "    fn draw(&self);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 组件实现 `Draw`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pub struct Button {\n",
    "    pub width: u32,\n",
    "    pub height: u32,\n",
    "    pub label: String,\n",
    "}\n",
    "\n",
    "impl Draw for Button {\n",
    "    fn draw(&self) {\n",
    "        println!(\"draw Button: {} ({}×{})\", self.label, self.width, self.height);\n",
    "    }\n",
    "}\n",
    "\n",
    "pub struct SelectBox {\n",
    "    pub width: u32,\n",
    "    pub height: u32,\n",
    "    pub options: Vec<String>,\n",
    "}\n",
    "\n",
    "impl Draw for SelectBox {\n",
    "    fn draw(&self) {\n",
    "        println!(\"draw SelectBox: {:?} ({}×{})\", self.options, self.width, self.height);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 特征对象的两种常见形态\n",
    "  - `dyn` 只在类型位置出现；\n",
    "  - `Box::new(value)` / `&value` 会自动转换成对应的特征对象；\n",
    "  - 函数内部通过 vtable 调度到具体实现。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn draw_boxed(x: Box<dyn Draw>) {\n",
    "    x.draw();            // 拥有所有权，智能指针指向堆上的数据\n",
    "}\n",
    "\n",
    "fn draw_borrowed(x: &dyn Draw) {\n",
    "    x.draw();            // 只借用，不转移所有权\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> `Box<T>` 在后面章节会[详细讲解](https://course.rs/advance/smart-pointer/box.html)，大家现在把它当成一个引用即可，只不过它包裹的值会被强制分配在堆上。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 使用特征对象构建异构 UI 容器\n",
    "  - `Vec<Box<dyn Draw>>` 可以混合存放不同组件，只要它们实现了 `Draw`；\n",
    "  - 动态分发带来灵活性，代价是不能进行某些编译期优化。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pub struct Screen {\n",
    "    pub components: Vec<Box<dyn Draw>>,\n",
    "}\n",
    "\n",
    "impl Screen {\n",
    "    pub fn run(&self) {\n",
    "        for component in &self.components {\n",
    "            component.draw();\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 与泛型的对比\n",
    "  - 泛型版 `Vec<T>` 必须存放 **同一种**类型（全是 `Button` 或全是 `SelectBox`）；\n",
    "  - 优势是静态分发、性能最佳；\n",
    "  - 选择依据：是否需要在同一容器中混合多种类型。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 可运行示例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "draw f64: 1.10\n",
       "draw u8: 8\n",
       "draw f64: 1.10\n",
       "draw u8: 8\n",
       "draw SelectBox: [\"Yes\", \"Maybe\", \"No\"] (75×10)\n",
       "draw Button: OK (50×10)\n",
       "draw Button: Submit (120×32)\n",
       "draw Button: Cancel (90×32)\n"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd trait_object && cargo run -q"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 编译期安全保障\n",
    "  - 仅实现了 `Draw` 的类型才允许进入 `Vec<Box<dyn Draw>>`；\n",
    "  - 若尝试 `Box::new(String::from(\"Hi\"))`，编译器会报错提醒缺少 `Draw` 实现；\n",
    "  - 类似鸭子类型，但在编译期就能确保“行为存在”，避免运行时失败。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "the trait bound `String: Draw` is not satisfied",
     "output_type": "error",
     "traceback": [
      "            Box::new(String::from(\"Hi\")),",
      "\u001b[91m            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m \u001b[94mthe trait `Draw` is not implemented for `String`\u001b[0m",
      "the trait bound `String: Draw` is not satisfied",
      "\u001b[1mhelp\u001b[0m: the trait `Draw` is implemented for `Button`"
     ]
    }
   ],
   "source": [
    "trait Draw {\n",
    "    fn draw(&self);\n",
    "}\n",
    "\n",
    "struct Button;\n",
    "\n",
    "impl Draw for Button {\n",
    "    fn draw(&self) {\n",
    "        println!(\"drawing Button\");\n",
    "    }\n",
    "}\n",
    "\n",
    "struct Screen {\n",
    "    components: Vec<Box<dyn Draw>>,\n",
    "}\n",
    "\n",
    "impl Screen {\n",
    "    fn run(&self) {\n",
    "        for component in &self.components {\n",
    "            component.draw();\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let screen = Screen {\n",
    "        components: vec![\n",
    "            Box::new(Button),\n",
    "            // 试图将 String 当成特征对象使用（错误）\n",
    "            Box::new(String::from(\"Hi\")),\n",
    "        ],\n",
    "    };\n",
    "\n",
    "    screen.run();\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 使用注意事项\n",
    "  - 仅“对象安全”的 trait 才能创建特征对象：方法不能返回 `Self` 或包含泛型参数；\n",
    "  - 不能单独使用 `dyn Draw` 作为函数参数或局部变量类型，需要通过引用或指针包裹："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 特征对象的动态分发"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![静态分发 Box<T> 和动态分发 Box<dyn Trait> 的区别](./images/box.svg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**`Box<T>`**：只需要一个指针 `ptr` 指向堆上的具体类型 `T`，调用方法时编译期就已确定（静态分发）。<br/>\n",
    "**`Box<dyn Trait>`**：除了数据指针 `ptr`，还多一个指向虚表的指针 `vptr`。\n",
    "- 虚表（vtable）里保存该具体类型的析构函数、大小、对齐以及实现的特征方法。\n",
    "- 运行期通过 `vptr` 找到实际要调用的方法（动态分发）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `Self` 与 `self`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `self`指代的就是当前的实例对象，也就是 `button.draw()` 中的 `button` 实例，\n",
    "- `Self` 则指代的是 `Button` 类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait Draw {\n",
    "    fn draw(&self) -> Self;\n",
    "}\n",
    "\n",
    "#[derive(Clone)]\n",
    "struct Button;\n",
    "impl Draw for Button {\n",
    "    fn draw(&self) -> Self {\n",
    "        return self.clone()\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let button = Button;\n",
    "    let newb = button.draw();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 特征对象的限制"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**并非所有特征都能做成特征对象**：必须满足“对象安全”。\n",
    "\n",
    "**对象安全条件**（每个方法都必须满足）：\n",
    "\n",
    "1. 返回类型不能是 `Self`。\n",
    "2. 方法不能带泛型参数。\n",
    "\n",
    "**原因**：特征对象会发生 **类型擦除**（type erasure），即运行时不再保留具体实现类型；若方法返回 `Self` 或依赖泛型参数，运行时就无法确定实际类型。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "标准库中的 `Clone` 特征就不符合对象安全的要求：\n",
    "\n",
    "```rust\n",
    "pub trait Clone {\n",
    "    fn clone(&self) -> Self;\n",
    "}\n",
    "```\n",
    "\n",
    "因为它的其中一个方法，返回了 `Self` 类型，因此它是对象不安全的。\n",
    "\n",
    "`String` 类型实现了 `Clone` 特征， `String` 实例上调用 `clone` 方法时会得到一个 `String` 实例。类似的，当调用 `Vec<T>` 实例的 `clone` 方法会得到一个 `Vec<T>` 实例。`clone` 的签名需要知道什么类型会代替 `Self`，因为这是它的返回值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "the trait `Clone` is not dyn compatible",
     "output_type": "error",
     "traceback": [
      "    components: Vec<Box<dyn Clone>>,",
      "\u001b[91m                        ^^^^^^^^^\u001b[0m \u001b[94m`Clone` is not dyn compatible\u001b[0m",
      "the trait `Clone` is not dyn compatible"
     ]
    },
    {
     "ename": "Error",
     "evalue": "the trait `Clone` is not dyn compatible",
     "output_type": "error",
     "traceback": [
      "        components: vec![",
      "            Box::new(String::from(\"Hello\")),",
      "            Box::new(vec![1, 2, 3]),",
      "        ],",
      "\u001b[91m                    \u001b[0m \u001b[94m`Clone` is not dyn compatible\u001b[0m",
      "the trait `Clone` is not dyn compatible"
     ]
    },
    {
     "ename": "Error",
     "evalue": "the trait `Clone` is not dyn compatible",
     "output_type": "error",
     "traceback": [
      "        components: vec![",
      "            Box::new(String::from(\"Hello\")),",
      "            Box::new(vec![1, 2, 3]),",
      "        ],",
      "\u001b[91m                    \u001b[0m \u001b[94m`Clone` is not dyn compatible\u001b[0m",
      "the trait `Clone` is not dyn compatible"
     ]
    },
    {
     "ename": "Error",
     "evalue": "the trait `Clone` is not dyn compatible",
     "output_type": "error",
     "traceback": [
      "        components: vec![",
      "            Box::new(String::from(\"Hello\")),",
      "            Box::new(vec![1, 2, 3]),",
      "        ],",
      "\u001b[91m                    \u001b[0m \u001b[94m`Clone` is not dyn compatible\u001b[0m",
      "the trait `Clone` is not dyn compatible"
     ]
    }
   ],
   "source": [
    "struct Screen {\n",
    "    components: Vec<Box<dyn Clone>>,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let screen = Screen {\n",
    "        components: vec![\n",
    "            Box::new(String::from(\"Hello\")),\n",
    "            Box::new(vec![1, 2, 3]),\n",
    "        ],\n",
    "    };\n",
    "\n",
    "    // 即便不调用任何方法，只要试图将 Clone 当作特征对象，就会编译失败。\n",
    "    let _ = screen;\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## * 深入了解特征\n",
    "\n",
    "- https://course.rs/basic/trait/advance-trait.html\n",
    "- https://practice-zh.course.rs/generics-traits/advanced-traits.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/generics-traits/advanced-trait.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### * 关联类型 / Associated types"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 Rust 里，**关联类型**是在 trait 内声明的类型占位符。实现该 trait 的具体类型会为这些占位符指定实际的类型。关联类型能让 trait 的使用者在调用 API 时不必显式传入类型参数，从而获得更简单、可读性更好的语法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "常见用途\n",
    "\n",
    "- **迭代器 (`Iterator::Item`)**\n",
    "- **转换 trait (`From`, `Into`, `TryFrom`, `TryInto`)**：`type Error`\n",
    "- **I/O 操作 (`Read`, `Write`)**\n",
    "- **标准库中的 `Future` trait**：`type Output`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait Iterator {\n",
    "    type Item;\n",
    "\n",
    "    fn next(&mut self) -> Option<Self::Item>;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `type Item;` 是关联类型声明。\n",
    "- 任何实现 `Iterator` 的类型都必须指定 `Item` 的具体类型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 实现示例：\n",
    "\n",
    "struct Counter {\n",
    "    current: u32,\n",
    "    end: u32,\n",
    "}\n",
    "\n",
    "impl Iterator for Counter {\n",
    "    type Item = u32;\n",
    "\n",
    "    fn next(&mut self) -> Option<Self::Item> {\n",
    "        if self.current < self.end {\n",
    "            let result = self.current;\n",
    "            self.current += 1;\n",
    "            Some(result)\n",
    "        } else {\n",
    "            None\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**与泛型参数的对比**\n",
    "- 当一个 trait 内部需要多个相关类型时，使用关联类型可避免泛型参数带来的“泛型污染”。\n",
    "\n",
    "| 特性                   | 泛型参数                       | 关联类型                     |\n",
    "| ---------------------- | ------------------------------ | ---------------------------- |\n",
    "| 使用场景               | 函数、结构体、枚举、trait      | 只能在 trait 中              |\n",
    "| 调用时显式指定类型参数 | 通常需要（如 `Foo::<T>::bar`） | 一般不需要（如 `foo.bar()`） |\n",
    "| 可读性                 | 在复杂 trait 中会很繁琐        | 更简洁、易读                 |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**默认类型与类型别名**\n",
    "\n",
    "- Rust 允许为关联类型提供默认值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait MyTrait {\n",
    "    type Error = ();\n",
    "    fn do_something(&self) -> Result<(), Self::Error>;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 实现者可以保留默认值，也可以覆盖："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Foo;\n",
    "impl MyTrait for Foo {\n",
    "    // 使用默认的 ()\n",
    "}\n",
    "\n",
    "struct Bar;\n",
    "impl MyTrait for Bar {\n",
    "    type Error = String; // 覆盖默认值\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**类型别名（Trait Alias）**\n",
    "\n",
    "- 在实现复杂 trait 时，可用 `type` 为泛型关联类型命名，配合 `where` 约束："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait Graph {\n",
    "    type Node;\n",
    "    type Edge;\n",
    "    fn edges(&self, node: &Self::Node) -> Vec<Self::Edge>;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 调用时无需显式写类型参数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn process<G: Graph>(graph: &G, node: &G::Node) {\n",
    "    for edge in graph.edges(node) {\n",
    "        // 使用 edge\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**复杂场景：关联类型与生命周期**\n",
    "\n",
    "- 关联类型可以包含泛型或生命周期参数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait StreamingIterator {\n",
    "    type Item<'a>\n",
    "    where\n",
    "        Self: 'a;\n",
    "\n",
    "    fn next(&mut self) -> Option<Self::Item<'_>>;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这种模式常见于支持 [Generic Associated Types (GATs)](https://rust-lang.github.io/generic-associated-types-initiative/explainer/motivation.html) 的场景，用于描述与生命周期相关的关联类型。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**何时使用关联类型？**\n",
    "\n",
    "- trait 描述的功能需要返回或操作某个“内部”的类型，但希望调用方无需关心类型细节。\n",
    "- 类型之间存在强绑定关系（例如图的节点和边），使用关联类型可以让 trait 实现者定义这些关系。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### * 默认泛型类型参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**概念**：为泛型参数提供默认类型，如 `trait Add<RHS = Self>`。调用时若未显式指定 `RHS`，会自动使用默认值。\n",
    "\n",
    "**好处**\n",
    "\n",
    "1. **减少样板代码**：同类型操作时可直接 `impl Add`，无需写 `impl Add<Self>`。\n",
    "2. **向后兼容扩展**：新加泛型参数时设置默认类型，旧代码无需修改。\n",
    "\n",
    "**应用场景**：运算符重载（`std::ops` 中的特征）、需要兼容既有代码的库扩展等。\n",
    "\n",
    "**要点**：默认参数可覆盖；当操作涉及不同类型时，需要显式指定具体类型（如 `impl Add<Meters> for Millimeters`）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 1. 依赖默认类型参数（RHS = Self）\n",
    "\n",
    "use std::ops::Add;\n",
    "\n",
    "#[derive(Debug, PartialEq)]\n",
    "struct Point {\n",
    "    x: i32,\n",
    "    y: i32,\n",
    "}\n",
    "\n",
    "// 使用默认的 RHS = Self\n",
    "impl Add for Point {\n",
    "    type Output = Point;\n",
    "\n",
    "    fn add(self, rhs: Point) -> Point {\n",
    "        Point {\n",
    "            x: self.x + rhs.x,\n",
    "            y: self.y + rhs.y,\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let a = Point { x: 1, y: 2 };\n",
    "    let b = Point { x: 3, y: 4 };\n",
    "    assert_eq!(a + b, Point { x: 4, y: 6 });\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 2. 覆盖默认类型参数\n",
    "\n",
    "use std::ops::Add;\n",
    "\n",
    "#[derive(Debug, PartialEq)]\n",
    "struct Millimeters(u32);\n",
    "\n",
    "#[derive(Debug, PartialEq)]\n",
    "struct Meters(u32);\n",
    "\n",
    "// 覆盖默认 RHS，显式指定为 Meters\n",
    "impl Add<Meters> for Millimeters {\n",
    "    type Output = Millimeters;\n",
    "\n",
    "    fn add(self, rhs: Meters) -> Millimeters {\n",
    "        Millimeters(self.0 + rhs.0 * 1_000)\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let length = Millimeters(500);\n",
    "    let extra = Meters(2);\n",
    "    assert_eq!(length + extra, Millimeters(2_500));\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 调用同名的方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **类型方法优先**：直接调用实例方法时，默认使用类型自身实现的版本。\n",
    "- **调用特征方法**：用 `Trait::method(&instance)` 显式指定特征即可。\n",
    "- **无 `self` 的关联函数**：需借助完全限定语法 `<Type as Trait>::function()` 来消歧。\n",
    "- **使用场景**：同名方法/函数冲突且编译器无法推断目标实现时，完全限定语法最可靠。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait Pilot {\n",
    "    fn fly(&self);\n",
    "}\n",
    "\n",
    "trait Wizard {\n",
    "    fn fly(&self);\n",
    "}\n",
    "\n",
    "struct Human;\n",
    "\n",
    "impl Pilot for Human {\n",
    "    fn fly(&self) {\n",
    "        println!(\"This is your captain speaking.\");\n",
    "    }\n",
    "}\n",
    "\n",
    "impl Wizard for Human {\n",
    "    fn fly(&self) {\n",
    "        println!(\"Up!\");\n",
    "    }\n",
    "}\n",
    "\n",
    "impl Human {\n",
    "    fn fly(&self) {\n",
    "        println!(\"*waving arms furiously*\");\n",
    "    }\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**优先调用类型上的方法**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "*waving arms furiously*\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "{\n",
    "    let person = Human;\n",
    "    person.fly();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**调用特征上的方法**\n",
    "- 调用特征的方法，需要使用显式调用的语法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This is your captain speaking.\n",
      "Up!\n",
      "*waving arms furiously*\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let person = Human;\n",
    "    Pilot::fly(&person); // 调用Pilot特征上的方法\n",
    "    Wizard::fly(&person); // 调用Wizard特征上的方法\n",
    "    person.fly(); // 调用Human类型自身的方法\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "因为 `fly` 方法的参数是 `self`，当显式调用时，编译器就可以根据调用的类型( `self` 的类型)决定具体调用哪个方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**完全限定语法**\n",
    "- 完全限定语法是调用函数最为明确的方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 第一个参数是方法接收器 receiver （三种 self），只有方法才拥有，例如关联函数就没有 receiver\n",
    "\n",
    "<Type as Trait>::function(receiver_if_method, next_arg, ...); // "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "trait Animal {\n",
    "    fn baby_name() -> String;\n",
    "}\n",
    "\n",
    "struct Dog;\n",
    "\n",
    "impl Dog {\n",
    "    fn baby_name() -> String {\n",
    "        String::from(\"Spot\")\n",
    "    }\n",
    "}\n",
    "\n",
    "impl Animal for Dog {\n",
    "    fn baby_name() -> String {\n",
    "        String::from(\"puppy\")\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A baby dog is called a Spot\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    println!(\"A baby dog is called a {}\", Dog::baby_name());\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A baby dog is called a puppy\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    println!(\"A baby dog is called a {}\", <Dog as Animal>::baby_name());\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 特征定义中的特征约束"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在特征定义中通过 `trait A: B` 指定“基特征”，要求实现者先实现 `B` 才能实现 `A`，从而在 `A` 的方法里安心调用 `B` 提供的功能（如 `Display` 的 `to_string`）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fmt::Display;\n",
    "\n",
    "trait OutlinePrint: Display {\n",
    "    fn outline_print(&self) {\n",
    "        let output = self.to_string();\n",
    "        let len = output.len();\n",
    "        println!(\"{}\", \"*\".repeat(len + 4));\n",
    "        println!(\"*{}*\", \" \".repeat(len + 2));\n",
    "        println!(\"* {} *\", output);\n",
    "        println!(\"*{}*\", \" \".repeat(len + 2));\n",
    "        println!(\"{}\", \"*\".repeat(len + 4));\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "`Point` doesn't implement `std::fmt::Display`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m `Point` doesn't implement `std::fmt::Display`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_6:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249mi\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mO\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mP\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mP\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                         \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m the trait `std::fmt::Display` is not implemented for `Point`",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;115mNote\u001b[0m: required by this bound in `OutlinePrint`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "struct Point {\n",
    "    x: i32,\n",
    "    y: i32,\n",
    "}\n",
    "\n",
    "impl OutlinePrint for Point {}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fmt;\n",
    "\n",
    "struct Point {\n",
    "    x: i32,\n",
    "    y: i32,\n",
    "}\n",
    "\n",
    "impl fmt::Display for Point {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        write!(f, \"({}, {})\", self.x, self.y)\n",
    "    }\n",
    "}\n",
    "\n",
    "impl OutlinePrint for Point {}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### * 在外部类型上实现外部特征(newtype)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过为目标类型包一层本地新类型（newtype），你就能在不违背孤儿规则的前提下为外部类型实现外部特征，同时保持零运行时开销。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 凸显了孤儿规则：不能“跨 crate”直接组合外部类型和外部特征。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "only traits defined in the current crate can be implemented for types defined outside of the crate",
     "output_type": "error",
     "traceback": [
      "impl<T> fmt::Display for Vec<T> {",
      "\u001b[91m                         ^^^^^^\u001b[0m \u001b[94m`Vec` is not defined in the current crate\u001b[0m",
      "impl<T> fmt::Display for Vec<T> {",
      "\u001b[91m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m \u001b[94merror: only traits defined in the current crate can be implemented for types defined outside of the crate\u001b[0m",
      "only traits defined in the current crate can be implemented for types defined outside of the crate"
     ]
    }
   ],
   "source": [
    "// 直接为外部类型实现外部特征（违反孤儿规则）\n",
    "\n",
    "use std::fmt;\n",
    "\n",
    "// 编译错误：无法在本 crate 中为 Vec<T> 实现 Display\n",
    "impl<T> fmt::Display for Vec<T> {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n",
    "        write!(f, \"[Vec]\")\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let v = vec![1, 2, 3];\n",
    "    println!(\"{}\", v);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "-  newtype 创建本地类型，再实现 trait，规避限制且零运行时开销。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "w = [hello, world]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 使用 newtype 模式包裹，再实现外部特征\n",
    "\n",
    "use std::fmt;\n",
    "\n",
    "// 新类型（本地定义）包裹外部类型 Vec<String>\n",
    "struct Wrapper(Vec<String>);\n",
    "\n",
    "impl fmt::Display for Wrapper {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n",
    "        write!(f, \"[{}]\", self.0.join(\", \"))\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let w = Wrapper(vec![String::from(\"hello\"), String::from(\"world\")]);\n",
    "    println!(\"w = {}\", w); // 输出：w = [hello, world]\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `Deref` 扩展让新类型几乎像原始 `Vec` 那样使用，同时保留自定义控制权"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "len = 2\n",
      "w = [hello, world]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 实现 Deref 以便透明访问内部 Vec\n",
    "\n",
    "use std::fmt;\n",
    "use std::ops::Deref;\n",
    "\n",
    "struct Wrapper(Vec<String>);\n",
    "\n",
    "impl fmt::Display for Wrapper {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n",
    "        write!(f, \"[{}]\", self.join(\", \"))\n",
    "    }\n",
    "}\n",
    "\n",
    "impl Deref for Wrapper {\n",
    "    type Target = Vec<String>;\n",
    "\n",
    "    fn deref(&self) -> &Self::Target {\n",
    "        &self.0\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let w = Wrapper(vec![String::from(\"hello\"), String::from(\"world\")]);\n",
    "\n",
    "    // 通过 Deref 透明调用 Vec<String> 的方法\n",
    "    println!(\"len = {}\", w.len());\n",
    "    println!(\"w = {}\", w);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.9. [集合类型](https://course.rs/basic/collections/intro.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 动态数组 Vector\n",
    "\n",
    "- https://course.rs/basic/collections/vector.html\n",
    "- https://practice-zh.course.rs/collections/vector.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/collections/Vector.md\n",
    "\n",
    "`Vec<T>` 是 Rust 中按顺序紧密存放同类型元素的动态数组，既高效访问又能灵活扩容，是实现同类数据列表的首选容器。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建动态数组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Vec::new**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let v: Vec<i32> = Vec::new(); // v 被显式地声明了类型 Vec<i32>，这是因为 Rust 编译器无法从 Vec::new() 中得到任何关于类型的暗示信息，因此也无法推导出 v 的具体类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let mut v = Vec::new();\n",
    "v.push(1); // 编译器通过 v.push(1)，推测出 v 中的元素类型是 i32，因此推导出 v 的类型是 Vec<i32>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 如果预先知道要存储的元素个数，可以使用 `Vec::with_capacity(capacity)` 创建动态数组，这样可以避免因为插入大量新数据导致频繁的内存分配和拷贝，提升性能"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**vec![]**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let v = vec![1, 2, 3]; // 在创建同时给予初始化值\n",
    "                       // 此处的 v 也无需标注类型，编译器只需检查它内部的元素即可自动推导出 v 的类型是 Vec<i32>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 更新 Vector"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let mut v = Vec::new(); // 向数组尾部添加元素; 与其它类型一样，必须将 v 声明为 mut 后，才能进行修改\n",
    "v.push(1);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Vector 与其元素共存亡"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 跟结构体一样，Vector 类型在超出作用域范围后，会被自动删除\n",
    "\n",
    "{\n",
    "    let v = vec![1, 2, 3];\n",
    "\n",
    "    // ...\n",
    "} // <- v超出作用域并在此处被删除"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当 `Vector` 被删除后，它内部存储的所有内容也会随之被删除。目前来看，这种解决方案简单直白，但是当 `Vector` 中的元素被引用后，事情可能会没那么简单"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 从 Vector 中读取元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "let v = vec![1, 2, 3, 4, 5];\n",
    "\n",
    "let third: &i32 = &v[2]; // 1. 通过下标索引访问\n",
    "println!(\"第三个元素是 {}\", third);\n",
    "\n",
    "match v.get(2) { // 2. 使用 get 方法, 返回了 Option<&T>\n",
    "    Some(third) => println!(\"第三个元素是 {third}\"),\n",
    "    None => println!(\"去你的第三个元素，根本没有！\"),\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**下标索引与 .get 的区别**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:175:26:\n",
      "index out of bounds: the len is 5 but the index is 100\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: core::panicking::panic_bounds_check\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:280:5\n",
      "   3: ctx::run_user_code_10::{{closure}}\n",
      "   4: __rust_try.llvm.9526564572246430071\n",
      "   5: std::panic::catch_unwind\n",
      "   6: run_user_code_10\n",
      "   7: evcxr::runtime::Runtime::run_loop\n",
      "   8: evcxr::runtime::runtime_hook\n",
      "   9: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "// &v[100] 的访问方式会导致程序报错退出，因为发生了数组越界访问\n",
    "\n",
    "{\n",
    "  let v = vec![1, 2, 3, 4, 5];\n",
    "\n",
    "  let does_not_exist = &v[100];\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// v.get 就不会，它在内部做了处理，有值的时候返回 Some(T)，无值的时候返回 None\n",
    "\n",
    "{\n",
    "  let v = vec![1, 2, 3, 4, 5];\n",
    "\n",
    "  let does_not_exist = v.get(100);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 同时借用多个数组元素"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 `Vec<T>` 中，不能在持有元素的不可变借用同时再进行可变借用（如 `push`），因为底层可能重新分配内存让原引用失效，Rust 因此禁止这种用法以确保内存安全。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot borrow `v` as mutable because it is also borrowed as immutable",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0502] Error:\u001b[0m cannot borrow `v` as mutable because it is also borrowed as immutable",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_19:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;100mv\u001b[0m\u001b[38;5;249m[\u001b[0m\u001b[38;5;249m0\u001b[0m\u001b[38;5;249m]\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m immutable borrow occurs here",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mv\u001b[0m\u001b[38;5;54m.\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m6\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m   \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m       \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m mutable borrow occurs here",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m8 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mT\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;68mf\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mr\u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                                    \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                      \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m immutable borrow later used here",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "  let mut v = vec![1, 2, 3, 4, 5];\n",
    "\n",
    "  let first = &v[0]; //  first = &v[0] 进行了不可变借用\n",
    "\n",
    "  v.push(6); // v.push 进行了可变借用\n",
    "\n",
    "  println!(\"The first element is: {first}\"); // first 这个不可变借用在可变借用 v.push 后被使用了\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- [所有权和借用](https://course.rs/basic/ownership/borrowing.html#借用规则总结)\n",
    "- [引用的作用域](https://course.rs/basic/ownership/borrowing.html#可变引用与不可变引用不能同时存在)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 若读者想要更深入的了解 `Vec<T>`，可以看看[Rustonomicon](https://nomicon.purewhite.io/vec/vec.html)，其中从零手撸一个动态数组，非常适合深入学习。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 迭代遍历 Vector 中的元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 用下标的方式去遍历, 每次下标访问都会触发数组边界检查\n",
    "\n",
    "let v = vec![1, 2, 3];\n",
    "for i in &v {\n",
    "    println!(\"{i}\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "11\n",
      "12\n",
      "13\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 使用迭代的方式去遍历数组, 可以在迭代过程中，修改 Vector 中的元素\n",
    "\n",
    "let mut v = vec![1, 2, 3];\n",
    "for i in &mut v {\n",
    "    *i += 10\n",
    "}\n",
    "\n",
    "for i in &mut v {\n",
    "    println!(\"{i}\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 存储不同类型的元素"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "动态数组的元素必须类型相同"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "V4(\"127.0.0.1\")\n",
      "V6(\"::1\")\n"
     ]
    }
   ],
   "source": [
    "// 通过使用枚举类型来实现不同类型元素的存储\n",
    "\n",
    "#[derive(Debug)]\n",
    "enum IpAddr {\n",
    "    V4(String),\n",
    "    V6(String)\n",
    "}\n",
    "\n",
    "{\n",
    "    let v = vec![ // 数组 v 中存储了两种不同的 ip 地址，但是这两种都属于 IpAddr 枚举类型的成\n",
    "        IpAddr::V4(\"127.0.0.1\".to_string()),\n",
    "        IpAddr::V6(\"::1\".to_string())\n",
    "    ];\n",
    "\n",
    "    for ip in v {\n",
    "        show_addr(ip)\n",
    "    }\n",
    "}\n",
    "\n",
    "fn show_addr(ip: IpAddr) {\n",
    "    println!(\"{:?}\",ip);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ipv4: \"127.0.0.1\"\n",
      "ipv6: \"::1\"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 通过使用特征对象来实现不同类型元素的存储\n",
    "\n",
    "trait IpAddr {\n",
    "    fn display(&self);\n",
    "}\n",
    "\n",
    "struct V4(String);\n",
    "impl IpAddr for V4 {\n",
    "    fn display(&self) {\n",
    "        println!(\"ipv4: {:?}\",self.0)\n",
    "    }\n",
    "}\n",
    "struct V6(String); \n",
    "impl IpAddr for V6 { //为 V4 和 V6 都实现了特征 IpAddr\n",
    "    fn display(&self) {\n",
    "        println!(\"ipv6: {:?}\",self.0)\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let v: Vec<Box<dyn IpAddr>> = vec![ // 将V4 和 V6的实例用 Box::new 包裹后，存在了数组 v 中; 这里必须手动地指定类型：Vec<Box<dyn IpAddr>>，表示数组 v 存储的是特征 IpAddr 的对象\n",
    "        Box::new(V4(\"127.0.0.1\".to_string())),\n",
    "        Box::new(V6(\"::1\".to_string())),\n",
    "    ];\n",
    "\n",
    "    for ip in v {\n",
    "        ip.display();\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Vector 常用方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 场景                 | 方法/语法                  | 说明                           | 示例                                  |\n",
    "| -------------------- | -------------------------- | ------------------------------ | ------------------------------------- |\n",
    "| 创建有默认值的 `Vec` | `vec![value; count]`       | 用同一默认值填充指定长度       | `let v = vec![0; 3];`                 |\n",
    "| 从数组或切片构建     | `Vec::from(data)`          | 复制数组/切片到新的 `Vec`      | `let v = Vec::from([0, 0, 0]);`       |\n",
    "| 从迭代器收集         | `iter.collect::<Vec<_>>()` | 将迭代器转换为 `Vec`           | `let v = (0..3).collect::<Vec<_>>();` |\n",
    "| 预分配容量           | `Vec::with_capacity(cap)`  | 指定初始容量，避免频繁扩容     | `let mut v = Vec::with_capacity(10);` |\n",
    "| 批量追加元素         | `Vec::extend(iter)`        | 从任意可迭代对象追加数据       | `v.extend([1, 2, 3]);`                |\n",
    "| 确保容量             | `Vec::reserve(additional)` | 至少再留出 `additional` 个位置 | `v.reserve(100);`                     |\n",
    "| 收缩容量             | `Vec::shrink_to_fit()`     | 释放未使用的容量（按需使用）   | `v.shrink_to_fit();`                  |\n",
    "\n",
    "> ⚙️ 初始化时估算合适的容量并利用 `with_capacity`/`reserve`，能显著减少动态扩容导致的内存重分配与拷贝成本；更多操作参考标准库 `Vec` 文档。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 初始化 vec 的更多方式\n",
    "\n",
    "{\n",
    "    let v = vec![0; 3];   // 默认值为 0，初始长度为 3\n",
    "    let v_from = Vec::from([0, 0, 0]);\n",
    "    assert_eq!(v, v_from);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Vector 长度是: 3, 容量是: 10\n",
      "Vector（reserve） 长度是: 3, 容量是: 103\n",
      "Vector（shrink_to_fit） 长度是: 3, 容量是: 3\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 在初始化时就指定一个实际的预估容量，尽量减少可能的内存拷贝\n",
    "\n",
    "{\n",
    "    let mut v = Vec::with_capacity(10);\n",
    "    v.extend([1, 2, 3]);    // 附加数据到 v\n",
    "    println!(\"Vector 长度是: {}, 容量是: {}\", v.len(), v.capacity());\n",
    "\n",
    "    v.reserve(100);        // 调整 v 的容量，至少要有 100 的容量\n",
    "    println!(\"Vector（reserve） 长度是: {}, 容量是: {}\", v.len(), v.capacity());\n",
    "\n",
    "    v.shrink_to_fit();     // 释放剩余的容量，一般情况下，不会主动去释放容量\n",
    "    println!(\"Vector（shrink_to_fit） 长度是: {}, 容量是: {}\", v.len(), v.capacity());\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 常见的一些方法示例\n",
    "\n",
    "let mut v =  vec![1, 2];\n",
    "assert!(!v.is_empty());         // 检查 v 是否为空\n",
    "\n",
    "v.insert(2, 3);                 // 在指定索引插入数据，索引值不能大于 v 的长度， v: [1, 2, 3] \n",
    "assert_eq!(v.remove(1), 2);     // 移除指定位置的元素并返回, v: [1, 3]\n",
    "assert_eq!(v.pop(), Some(3));   // 删除并返回 v 尾部的元素，v: [1]\n",
    "assert_eq!(v.pop(), Some(1));   // v: []\n",
    "assert_eq!(v.pop(), None);      // 记得 pop 方法返回的是 Option 枚举值\n",
    "v.clear();                      // 清空 v, v: []\n",
    "\n",
    "let mut v1 = [11, 22].to_vec(); // append 操作会导致 v1 清空数据，增加可变声明\n",
    "v.append(&mut v1);              // 将 v1 中的所有元素附加到 v 中, v1: []\n",
    "v.truncate(1);                  // 截断到指定长度，多余的元素被删除, v: [11]\n",
    "v.retain(|x| *x > 10);          // 保留满足条件的元素，即删除不满足条件的元素\n",
    "\n",
    "let mut v = vec![11, 22, 33, 44, 55];\n",
    "// 删除指定范围的元素，同时获取被删除元素的迭代器, v: [11, 55], m: [22, 33, 44]\n",
    "let mut m: Vec<_> = v.drain(1..=3).collect();    \n",
    "\n",
    "let v2 = m.split_off(1);        // 指定索引处切分成两个 vec, m: [22], v2: [33, 44]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 可以像数组切片的方式获取 vec 的部分元素\n",
    "\n",
    "{\n",
    "    let v = vec![11, 22, 33, 44, 55];\n",
    "    let slice = &v[1..=3];\n",
    "    assert_eq!(slice, &[22, 33, 44]);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "更多细节，阅读 Vector 的[标准库文档](https://doc.rust-lang.org/std/vec/struct.Vec.html#)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Vector 的排序"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 数                                | 稳定性   | 比较方式                 | 额外内存                   | 类型/特征约束          | 注意事项                                                 |\n",
    "| --------------------------------- | -------- | ------------------------ | -------------------------- | ---------------------- | -------------------------------------------------------- |\n",
    "| `slice.sort()`                    | ✅ 稳定   | 自动使用元素实现的 `Ord` | 需要临时缓冲（约一半长度） | 元素类型必须实现 `Ord` | 适合整数、已实现 `Ord` 的结构体；保持相等元素原有顺序。  |\n",
    "| `slice.sort_by(a, b...)`          | ✅ 稳定   | 自定义比较函数           | 需要临时缓冲（约一半长度） | 闭包返回 `Ordering`    | 适合自定义排序逻辑、结构体按特定字段排序。               |\n",
    "| `slice.sort_unstable()`           | ❌ 非稳定 | 自动使用 `Ord`           | 原地排序，无额外分配       | 元素类型必须实现 `Ord` | 更快；适合不关心相等元素顺序的整数等全序类型。           |\n",
    "| `slice.sort_unstable_by(a, b...)` | ❌ 非稳定 | 自定义比较函数           | 原地排序，无额外分配       | 闭包返回 `Ordering`    | 性能优先的自定义排序；适合结构体按字段排序且不需稳定性。 |\n",
    "| `slice.sort_by_key(x)`            | ✅ 稳定   | 按提取的键（`key`）排序  | 需要临时缓冲（含键缓存）   | 依据键的 `Ord`         | 简洁的按键排序方式；键提取函数会对每个元素调用。         |\n",
    "\n",
    "\n",
    "📌 结构体若 `#[derive(Ord, Eq, PartialEq, PartialOrd)]`，即可直接用 `sort`/`sort_unstable`；不过需保证所有字段也实现这些 trait，且比较顺序按字段声明顺序进行。"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "是否需要保持相等元素顺序？\n",
    "├─ 是 → 使用稳定排序（sort/sort_by/sort_by_key）\n",
    "└─ 否 → 使用非稳定排序（sort_unstable/sort_unstable_by）性能更好\n",
    "\n",
    "类型是否实现了 Ord？\n",
    "├─ 是（如整数、字符串）→ 使用 sort() 或 sort_unstable()\n",
    "├─ 否但实现了 PartialOrd（如浮点数）→ 使用 sort_by + partial_cmp\n",
    "└─ 结构体 → \n",
    "    ├─ 所有字段都实现 Ord → derive Ord 后用 sort()\n",
    "    └─ 需要自定义逻辑 → 使用 sort_by 或 sort_by_key"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**整数数组的排序**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let mut vec = vec![1, 5, 10, 2, 15];    \n",
    "    vec.sort_unstable();    \n",
    "    assert_eq!(vec, vec![1, 2, 5, 10, 15]);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**浮点数数组的排序**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "the trait bound `f32: Ord` is not satisfied",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m the trait bound `f32: Ord` is not satisfied",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_8:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mb\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m               \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m the trait `Ord` is not implemented for `f32`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let mut vec = vec![1.0, 5.6, 10.3, 2.0, 15f32];    \n",
    "    vec.sort_unstable();    \n",
    "    assert_eq!(vec, vec![1.0, 2.0, 5.6, 10.3, 15f32]);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let mut vec = vec![1.0, 5.6, 10.3, 2.0, 15f32];    \n",
    "    vec.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap()); // 浮点数实现了 PartialOrd\n",
    "    assert_eq!(vec, vec![1.0, 2.0, 5.6, 10.3, 15f32]);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1.0, 2.0, 5.6, 10.3, 15.0]\n",
      "[1.0, NaN, 2.0, 5.6, NaN]\n",
      "[1.0, 2.0, 5.6]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    // 示例 1: 不含 NaN\n",
    "    let mut vec1 = vec![1.0, 5.6, 10.3, 2.0, 15f32];\n",
    "    vec1.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());\n",
    "    println!(\"{:?}\", vec1); // [1.0, 2.0, 5.6, 10.3, 15.0]\n",
    "    \n",
    "    // 示例 2: 包含 NaN\n",
    "    let mut vec2 = vec![1.0, f32::NAN, 5.6, 2.0, f32::NAN];\n",
    "    vec2.sort_by(|a, b| {\n",
    "        a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)\n",
    "    });\n",
    "    println!(\"{:?}\", vec2); \n",
    "    // NaN 会被放在某个位置（具体位置取决于实现）\n",
    "    \n",
    "    // 推荐做法, 示例 3: 过滤掉 NaN 后排序\n",
    "    let mut vec3 = vec![1.0, f32::NAN, 5.6, 2.0, f32::NAN];\n",
    "    vec3.retain(|x| !x.is_nan()); // 移除 NaN\n",
    "    vec3.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());\n",
    "    println!(\"{:?}\", vec3); // [1.0, 2.0, 5.6]\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**结构体排序**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Person { name: \"Al\", age: 30 }, Person { name: \"Al\", age: 60 }]\n"
     ]
    }
   ],
   "source": [
    "// 派生 Ord 特性\n",
    "\n",
    "#[derive(Debug, Ord, Eq, PartialEq, PartialOrd)]\n",
    "struct Person {\n",
    "    name: String,  // 优先按 name 比较\n",
    "    age: u32,      // name 相同时按 age 比较\n",
    "}\n",
    "\n",
    "let mut people = vec![\n",
    "    Person { name: \"Al\".to_string(), age: 60 },\n",
    "    Person { name: \"Al\".to_string(), age: 30 },\n",
    "];\n",
    "people.sort_unstable();\n",
    "\n",
    "\n",
    "println!(\"{:?}\", people); "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Person { name: \"Al\", age: 60 }, Person { name: \"Zoe\", age: 25 }]\n",
      "[Person { name: \"Zoe\", age: 25 }, Person { name: \"Al\", age: 60 }]\n"
     ]
    }
   ],
   "source": [
    "// 自定义比较函数\n",
    "\n",
    "#[derive(Debug)]\n",
    "struct Person {\n",
    "    name: String,\n",
    "    age: u32,\n",
    "}\n",
    "\n",
    "let mut people = vec![\n",
    "    Person { name: \"Zoe\".to_string(), age: 25 },\n",
    "    Person { name: \"Al\".to_string(), age: 60 },\n",
    "];\n",
    "\n",
    "// 按年龄倒序\n",
    "people.sort_unstable_by(|a, b| b.age.cmp(&a.age));\n",
    "println!(\"{:?}\", people); \n",
    "\n",
    "// 或使用 sort_by_key（升序）\n",
    "people.sort_by_key(|p| p.age);\n",
    "println!(\"{:?}\", people); "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## KV 存储 HashMap\n",
    "\n",
    "- https://course.rs/basic/collections/hashmap.html\n",
    "- https://practice-zh.course.rs/collections/hashmap.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/collections/Hashmap.md\n",
    "\n",
    "Rust 的 `HashMap<K, V>` 是标准库提供的键值映射集合，平均 O(1) 查询效率，与其他语言的 hash map／字典类似，方便通过键快速定位值。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建 HashMap"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 创建方式             | 适用场景         | 代码简洁度 | 性能   |\n",
    "| -------------------- | ---------------- | ---------- | ------ |\n",
    "| `new()` + `insert()` | 手动逐个插入     | 中等       | 正常   |\n",
    "| `with_capacity()`    | 预知容量         | 中等       | **优** |\n",
    "| `collect()`          | 从迭代器批量转换 | **高**     | 优     |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**最佳实践**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::collections::HashMap; // 必须手动引入; String 和 Vec 自动在作用域中，无需引入\n",
    "\n",
    "// ✅ 场景1: 逐步构建（容量已知）\n",
    "let mut config = HashMap::with_capacity(5);\n",
    "config.insert(\"host\", \"localhost\");\n",
    "config.insert(\"port\", \"8080\");\n",
    "\n",
    "// ✅ 场景2: 从现有数据转换\n",
    "let data = vec![(\"a\", 1), (\"b\", 2), (\"c\", 3)];\n",
    "let map: HashMap<_, _> = data.into_iter().collect();\n",
    "\n",
    "// ⚠️ 类型标注必不可少\n",
    "// let map = data.into_iter().collect(); // ❌ 编译错误"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**使用 `new()` 方法创建**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "类型: std::collections::hash::map::HashMap<&str, i32>\n",
      "{\n",
      "    \"河边捡的误以为是宝石的破石头\": 18,\n",
      "    \"蓝宝石\": 2,\n",
      "    \"红宝石\": 1,\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "use std::collections::HashMap;\n",
    "\n",
    "let mut my_gems = HashMap::new();\n",
    "my_gems.insert(\"红宝石\", 1);\n",
    "my_gems.insert(\"蓝宝石\", 2);\n",
    "my_gems.insert(\"河边捡的误以为是宝石的破石头\", 18);\n",
    "// 类型: HashMap<&str, i32>\n",
    "\n",
    "println!(\"类型: {}\", std::any::type_name_of_val(&my_gems));\n",
    "println!(\"{:#?}\", my_gems); "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**使用迭代器 + collect() 方法创建**\n",
    "- 将 `Vec<(K, V)>` 转换为 `HashMap<K, V>`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"美国队\": 10,\n",
      "    \"日本队\": 50,\n",
      "    \"中国队\": 100,\n",
      "}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 笨方法（遍历插入）\n",
    "\n",
    "{\n",
    "  let teams_list = vec![\n",
    "      (\"中国队\".to_string(), 100),\n",
    "      (\"美国队\".to_string(), 10),\n",
    "      (\"日本队\".to_string(), 50),\n",
    "  ];\n",
    "\n",
    "  let mut teams_map = HashMap::new();\n",
    "  for team in &teams_list {\n",
    "      teams_map.insert(&team.0, team.1); // 逐个插入\n",
    "  }\n",
    "\n",
    "  println!(\"{:#?}\", teams_map);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"日本队\": 50,\n",
      "    \"美国队\": 10,\n",
      "    \"中国队\": 100,\n",
      "}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// Rusty 方法（collect 收集）\n",
    "\n",
    "{\n",
    "  let teams_list = vec![\n",
    "      (\"中国队\".to_string(), 100),\n",
    "      (\"美国队\".to_string(), 10),\n",
    "      (\"日本队\".to_string(), 50),\n",
    "  ];\n",
    "\n",
    "  let teams_map: HashMap<_, _> = teams_list.into_iter().collect();\n",
    "\n",
    "  println!(\"{:#?}\", teams_map);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 所有权转移"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "HashMap 的所有权规则与其它 Rust 类型完全一致：\n",
    "\n",
    "| 类型特征          | 行为                       | 所有权         |\n",
    "| ----------------- | -------------------------- | -------------- |\n",
    "| **实现了 `Copy`** | 值被**复制**进 HashMap     | 原变量仍可用 ✅ |\n",
    "| **未实现 `Copy`** | 所有权被**转移**给 HashMap | 原变量不可用 ❌ |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**最佳实践**\n",
    "\n",
    "**实现 `Copy` 的类型**（如整数）：直接插入，无需担心\n",
    "\n",
    "**未实现 `Copy` 的类型**（如 `String`）：\n",
    "\n",
    "- 需要保留原变量 → 使用 `.clone()`\n",
    "- 不再需要原变量 → 直接转移所有权\n",
    "\n",
    "**使用引用时**：确保引用的生命周期 ≥ HashMap 的生命周期"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**所有权转移（常见错误）**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "borrow of moved value: `name`",
     "output_type": "error",
     "traceback": [
      "  handsome_boys.insert(name, age);     // name 所有权转移！",
      "\u001b[91m                       ^^^^\u001b[0m \u001b[94mvalue moved here\u001b[0m",
      "  println!(\"因为过于无耻，{}已经被除名\", name); // ❌ 编译错误",
      "\u001b[91m                             ^^^^\u001b[0m \u001b[94mvalue borrowed here after move\u001b[0m",
      "  let name = String::from(\"Sunface\");  // String 未实现 Copy",
      "\u001b[91m      ^^^^\u001b[0m \u001b[94mmove occurs because `name` has type `String`, which does not implement the `Copy` trait\u001b[0m",
      "borrow of moved value: `name`",
      "\u001b[1mhelp\u001b[0m: consider cloning the value if the performance cost is acceptable\n\n.clone()"
     ]
    }
   ],
   "source": [
    "{\n",
    "  use std::collections::HashMap;\n",
    "\n",
    "  let name = String::from(\"Sunface\");  // String 未实现 Copy\n",
    "  let age = 18;                        // i32 实现了 Copy\n",
    "\n",
    "  let mut handsome_boys = HashMap::new();\n",
    "  handsome_boys.insert(name, age);     // name 所有权转移！\n",
    "\n",
    "  println!(\"因为过于无耻，{}已经被除名\", name); // ❌ 编译错误\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "还有，他的真实年龄远远不止18岁\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "  use std::collections::HashMap;\n",
    "\n",
    "  let name = String::from(\"Sunface\");  // String 未实现 Copy\n",
    "  let age = 18;                        // i32 实现了 Copy\n",
    "\n",
    "  let mut handsome_boys = HashMap::new();\n",
    "  handsome_boys.insert(name, age);     // name 所有权转移！\n",
    "\n",
    "  println!(\"还有，他的真实年龄远远不止{}岁\", age); // ✅ 正常\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**引用的生命周期问题**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot move out of `name` because it is borrowed",
     "output_type": "error",
     "traceback": [
      "  std::mem::drop(name);              // ❌ 手动释放 name",
      "\u001b[91m                 ^^^^\u001b[0m \u001b[94mmove out of `name` occurs here\u001b[0m",
      "  handsome_boys.insert(&name, age);  // 插入 name 的引用",
      "\u001b[91m                       ^^^^^\u001b[0m \u001b[94mborrow of `name` occurs here\u001b[0m",
      "  let name = String::from(\"Sunface\");",
      "\u001b[91m      ^^^^\u001b[0m \u001b[94mbinding `name` declared here\u001b[0m",
      "  println!(\"因为过于无耻，{:?}已经被除名\", handsome_boys); // ❌ 编译错误",
      "\u001b[91m                               ^^^^^^^^^^^^^\u001b[0m \u001b[94mborrow later used here\u001b[0m",
      "cannot move out of `name` because it is borrowed",
      "\u001b[1mhelp\u001b[0m: consider cloning the value if the performance cost is acceptable\n\n.clone()"
     ]
    }
   ],
   "source": [
    "{\n",
    "  use std::collections::HashMap;\n",
    "\n",
    "  let name = String::from(\"Sunface\");\n",
    "  let age = 18;\n",
    "\n",
    "  let mut handsome_boys = HashMap::new();\n",
    "  handsome_boys.insert(&name, age);  // 插入 name 的引用\n",
    "\n",
    "  std::mem::drop(name);              // ❌ 手动释放 name, HashMap 中的引用变成悬垂引用\n",
    "  println!(\"因为过于无耻，{:?}已经被除名\", handsome_boys); // ❌ 编译错误\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "原始 name 仍可用: Sunface\n",
      "HashMap: {\"Sunface\": 18}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// clone()\n",
    "\n",
    "{\n",
    "  use std::collections::HashMap;\n",
    "\n",
    "  let name = String::from(\"Sunface\");\n",
    "  let age = 18;\n",
    "\n",
    "  let mut handsome_boys = HashMap::new();\n",
    "  handsome_boys.insert(name.clone(), age); // 克隆一份\n",
    "\n",
    "  println!(\"原始 name 仍可用: {}\", name); // ✅ 正常\n",
    "  println!(\"HashMap: {:?}\", handsome_boys);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "HashMap: {\"Sunface\": 18}\n",
      "name 仍可用: Sunface\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 使用引用\n",
    "\n",
    "{\n",
    "  use std::collections::HashMap;\n",
    "\n",
    "  let name = String::from(\"Sunface\");\n",
    "  let age = 18;\n",
    "\n",
    "  let mut handsome_boys = HashMap::new();\n",
    "  handsome_boys.insert(&name, age); // 使用引用\n",
    "\n",
    "  // ✅ name 必须在 HashMap 使用期间保持有效\n",
    "  println!(\"HashMap: {:?}\", handsome_boys);\n",
    "  println!(\"name 仍可用: {}\", name);\n",
    "  // 不能在此之前 drop(name)\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "HashMap: {\"Sunface\": 18}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 转移所有权后不再使用原变量\n",
    "\n",
    "{\n",
    "  use std::collections::HashMap;\n",
    "\n",
    "  let name = String::from(\"Sunface\");\n",
    "  let age = 18;\n",
    "\n",
    "  let mut handsome_boys = HashMap::new();\n",
    "  handsome_boys.insert(name, age); // 转移所有权\n",
    "\n",
    "  // ✅ 之后只使用 HashMap，不再访问 name\n",
    "  println!(\"HashMap: {:?}\", handsome_boys);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 查询 HashMap"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 方法          | 返回类型         | 键不存在   | 用途                   |\n",
    "| ------------- | ---------------- | ---------- | ---------------------- |\n",
    "| `get(&k)`     | `Option<&V>`     | `None`     | 安全查询，返回引用     |\n",
    "| `get_mut(&k)` | `Option<&mut V>` | `None`     | 安全查询，返回可变引用 |\n",
    "| `[]` 运算符   | `&V`             | **panic!** | 直接访问（不安全）     |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 最佳实践"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 1. 使用 Option 处理可能不存在的键\n",
    "if let Some(score) = scores.get(&team_name) {\n",
    "    println!(\"分数: {}\", score);\n",
    "}\n",
    "\n",
    "// 2. 提供默认值\n",
    "let score = scores.get(&team_name).copied().unwrap_or(0);\n",
    "\n",
    "// 3. 遍历时使用借用\n",
    "for (key, value) in &scores {\n",
    "    // ...\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 1. 直接使用 [] 运算符（可能 panic）\n",
    "let score = &scores[&team_name];  // ⚠️ 危险\n",
    "\n",
    "// 2. 不必要的 clone\n",
    "let score = scores.get(&team_name).cloned();  // 对 Copy 类型用 copied 更好"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 基本查询：get 方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "score: Some(10)\n",
      "score: Some(10)\n",
      "score: None\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "  use std::collections::HashMap;\n",
    "\n",
    "  let mut scores = HashMap::new();\n",
    "  scores.insert(String::from(\"Blue\"), 10);\n",
    "  scores.insert(String::from(\"Yellow\"), 50);\n",
    "\n",
    "  let team_name = String::from(\"Blue\");\n",
    "  let score: Option<&i32> = scores.get(&team_name); // 返回的是借用 &i32: HashMap 保留数据的所有权, 你只是\"查看\"数据，不是\"拿走\"数据\n",
    "                                                    // 参数必须是引用 `&K`, get 方法签名要求引用\n",
    "  println!(\"score: {:?}\", score);\n",
    "\n",
    "  let score: Option<&i32> = scores.get(\"Blue\"); // String: Borrow<str>)\n",
    "  println!(\"score: {:?}\", score);\n",
    "\n",
    "  let score = scores.get(&String::from(\"Red\")); // None: 键不存在, 表示未找到\n",
    "  println!(\"score: {:?}\", score);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 获取值类型（非引用）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "score: 10\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "  use std::collections::HashMap;\n",
    "\n",
    "  let mut scores = HashMap::new();\n",
    "  scores.insert(String::from(\"Blue\"), 10);\n",
    "  scores.insert(String::from(\"Yellow\"), 50);\n",
    "\n",
    "  let team_name = String::from(\"Blue\");\n",
    "  let score: i32 = scores.get(&team_name).copied().unwrap_or(0);\n",
    "  println!(\"score: {:?}\", score);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 步骤 | 方法              | 输入           | 输出           | 说明                        |\n",
    "| ---- | ----------------- | -------------- | -------------- | --------------------------- |\n",
    "| 1    | `get(&team_name)` | `&String`      | `Option<&i32>` | 获取引用                    |\n",
    "| 2    | `.copied()`       | `Option<&i32>` | `Option<i32>`  | 复制值（需要类型实现 Copy） |\n",
    "| 3    | `.unwrap_or(0)`   | `Option<i32>`  | `i32`          | 如果是 None 返回默认值 0    |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "score: Some(10)\n",
      "score: 10\n",
      "score: 0\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "  use std::collections::HashMap;\n",
    "\n",
    "  let mut scores = HashMap::new();\n",
    "  scores.insert(String::from(\"Blue\"), 10);\n",
    "  scores.insert(String::from(\"Yellow\"), 50);\n",
    "\n",
    "  let team_name = String::from(\"Blue\");\n",
    "  let score: Option<&i32> = scores.get(&team_name);\n",
    "\n",
    "  let opt_val: Option<i32> = score.copied(); // 将 Option<&T> 转换为 Option<T>; T 必须实现 Copy 特征; self.map(|&x| x)\n",
    "  println!(\"score: {:?}\", opt_val);\n",
    "\n",
    "  let value: i32 = opt_val.unwrap_or(0); // 如果是 Some(v) 返回 v，如果是 None 返回默认值; 不会 panic（相比 unwrap()）\n",
    "  println!(\"score: {:?}\", value);\n",
    "\n",
    "  println!(\"score: {:?}\", None.unwrap_or(0));\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 遍历 HashMap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::collections::HashMap;\n",
    "\n",
    "let mut scores = HashMap::new();\n",
    "scores.insert(String::from(\"Blue\"), 10);\n",
    "scores.insert(String::from(\"Yellow\"), 50);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Yellow: 50\n",
      "Blue: 10\n",
      "Yellow: 60\n",
      "Blue: 20\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 1. 借用遍历（推荐）\n",
    "for (key, value) in &scores {\n",
    "    println!(\"{}: {}\", key, value);\n",
    "}\n",
    "// scores 仍可用\n",
    "\n",
    "// 2. 可变借用遍历\n",
    "for (key, value) in &mut scores {\n",
    "    *value += 10;  // 可以修改值\n",
    "}\n",
    "\n",
    "// 3. 转移所有权遍历\n",
    "for (key, value) in scores {\n",
    "    println!(\"{}: {}\", key, value);\n",
    "}\n",
    "// scores 已失效，不能再使用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 更新 HashMap 中的值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "score: {\"Blue\": 10}\n",
      "score: {\"Blue\": 20}\n",
      "score: {\"Blue\": 20, \"Yellow\": 5}\n",
      "score: {\"Blue\": 20, \"Yellow\": 5}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    use std::collections::HashMap;\n",
    "\n",
    "    let mut scores = HashMap::new();\n",
    "\n",
    "    scores.insert(\"Blue\", 10);\n",
    "    println!(\"score: {:?}\", scores);\n",
    "\n",
    "    // 覆盖已有的值\n",
    "    let old = scores.insert(\"Blue\", 20);\n",
    "    assert_eq!(old, Some(10));\n",
    "    println!(\"score: {:?}\", scores);\n",
    "\n",
    "    // 查询新插入的值\n",
    "    let new = scores.get(\"Blue\");\n",
    "    assert_eq!(new, Some(&20));\n",
    "\n",
    "    // 查询Yellow对应的值，若不存在则插入新值\n",
    "    let v = scores.entry(\"Yellow\").or_insert(5);\n",
    "    assert_eq!(*v, 5); // 不存在，插入5\n",
    "    println!(\"score: {:?}\", scores);\n",
    "\n",
    "    // 查询Yellow对应的值，若不存在则插入新值\n",
    "    let v = scores.entry(\"Yellow\").or_insert(50);\n",
    "    assert_eq!(*v, 5); // 已经存在，因此50没有插入\n",
    "    println!(\"score: {:?}\", scores);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "查询某个 `key` 对应的值，若不存在则插入新值，若存在则对已有的值进行更新"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\"wonderful\": 1, \"world\": 2, \"hello\": 1}\n"
     ]
    }
   ],
   "source": [
    "// 在文本中统计词语出现的次数：\n",
    "\n",
    "use std::collections::HashMap;\n",
    "\n",
    "let text = \"hello world wonderful world\";\n",
    "\n",
    "let mut map = HashMap::new();\n",
    "// 根据空格来切分字符串(英文单词都是通过空格切分)\n",
    "for word in text.split_whitespace() {\n",
    "    let count = map.entry(word).or_insert(0); // or_insert 返回了 &mut v 引用，因此可以通过该可变引用直接修改 map 中对应的值\n",
    "    *count += 1; // 使用 count 引用时，需要先进行解引用 *count，否则会出现类型不匹配\n",
    "}\n",
    "\n",
    "println!(\"{:?}\", map);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "新建一个 `map` 用于保存词语出现的次数，插入一个词语时会进行判断：若之前没有插入过，则使用该词语作 `Key`，插入次数 0 作为 `Value`，若之前插入过则取出之前统计的该词语出现的次数，对其加一。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 哈希函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "为什么叫\"哈希表\"？\n",
    "- **哈希函数**将 Key 转换为哈希值，用于存储和查询：\n",
    "\n",
    "```txt\n",
    "Key → 哈希函数 → 哈希值 → 存储位置\n",
    "\"Blue\" → hash() → 12345 → 内存地址\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Key 的两个要求\n",
    "\n",
    "- ✅ 必须实现 `Eq` 特征（可比较相等性）\n",
    "- ✅ 必须实现 `Hash` 特征（可计算哈希值）\n",
    "\n",
    "> f32 和 f64 浮点数，没有实现 `std::cmp::Eq` 特征，因此不可以用作 `HashMap` 的 `Key`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "哈希函数的权衡\n",
    "\n",
    "| 类型         | 特点                    | 适用场景              |\n",
    "| ------------ | ----------------------- | --------------------- |\n",
    "| **安全哈希** | 慢但防碰撞、防 DoS 攻击 | 标准库默认（SipHash） |\n",
    "| **快速哈希** | 快但安全性低            | 高性能需求（[ahash](https://github.com/tkaitchuck/ahash)）   |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**哪些类型可以做 Key？**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::collections::HashMap;\n",
    "\n",
    "// 明确指定 Key 和 Value 类型\n",
    "let mut int_map: HashMap<i32, &str> = HashMap::new();\n",
    "int_map.insert(1, \"整数\");\n",
    "int_map.insert(2, \"数字\");\n",
    "\n",
    "let mut str_map: HashMap<&str, &str> = HashMap::new();\n",
    "str_map.insert(\"key\", \"字符串\");\n",
    "\n",
    "let mut bool_map: HashMap<bool, &str> = HashMap::new();\n",
    "bool_map.insert(true, \"布尔\");\n",
    "\n",
    "let mut char_map: HashMap<char, &str> = HashMap::new();\n",
    "char_map.insert('a', \"字符\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Some(\"整数\")\n",
      "\n",
      "{\n",
      "    Bool(\n",
      "        true,\n",
      "    ): \"布尔\",\n",
      "    Char(\n",
      "        'a',\n",
      "    ): \"字符\",\n",
      "    Str(\n",
      "        \"key\",\n",
      "    ): \"字符串\",\n",
      "    Int(\n",
      "        1,\n",
      "    ): \"整数\",\n",
      "}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 混合类型使用枚举\n",
    "\n",
    "use std::collections::HashMap;\n",
    "\n",
    "#[derive(Debug, PartialEq, Eq, Hash)]\n",
    "enum Key {\n",
    "    Int(i32),\n",
    "    Str(String),\n",
    "    Bool(bool),\n",
    "    Char(char),\n",
    "}\n",
    "\n",
    "let mut map = HashMap::new();\n",
    "\n",
    "map.insert(Key::Int(1), \"整数\");\n",
    "map.insert(Key::Str(\"key\".to_string()), \"字符串\");\n",
    "map.insert(Key::Bool(true), \"布尔\");\n",
    "map.insert(Key::Char('a'), \"字符\");\n",
    "\n",
    "println!(\"{:?}\\n\", map.get(&Key::Int(1)));  // Some(\"整数\")\n",
    "\n",
    "println!(\"{:#?}\", map)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "false\n"
     ]
    }
   ],
   "source": [
    "// 为什么浮点数不行？\n",
    "\n",
    "let a = 0.1 + 0.2;\n",
    "let b = 0.3;\n",
    "println!(\"{}\", a == b);  // false！（精度问题）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**自定义类型做 Key**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Some(\"原点\")\n"
     ]
    }
   ],
   "source": [
    "use std::collections::HashMap;\n",
    "\n",
    "// 自动派生 Eq 和 Hash\n",
    "#[derive(Debug, PartialEq, Eq, Hash)]\n",
    "struct Point {\n",
    "    x: i32,\n",
    "    y: i32,\n",
    "}\n",
    "\n",
    "let mut positions = HashMap::new();\n",
    "\n",
    "positions.insert(Point { x: 0, y: 0 }, \"原点\");\n",
    "positions.insert(Point { x: 1, y: 1 }, \"对角\");\n",
    "\n",
    "let origin = Point { x: 0, y: 0 };\n",
    "println!(\"{:?}\", positions.get(&origin));  // Some(\"原点\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.11. 返回值和错误处理\n",
    "\n",
    "- https://course.rs/basic/result-error/intro.html\n",
    "\n",
    "Rust 将错误分为可恢复（用 `Result<T, E>`）与不可恢复（用 `panic!`）两类，体现其承认错误必然性并要求开发者提前处理的设计哲学。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## panic! 深入剖析\n",
    "\n",
    "- https://course.rs/basic/result-error/panic.html\n",
    "- https://practice-zh.course.rs/result-panic/panic.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/result-panic/panic.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### panic! 与不可恢复错误"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 场景                             | 触发条件/描述                               | 示例代码片段                                   |\n",
    "| -------------------------------- | ------------------------------------------- | ---------------------------------------------- |\n",
    "| 显式 `panic!` 调用               | 程序主动终止                                | `panic!(\"Something went terribly wrong!\");`    |\n",
    "| 数组/切片越界                    | 使用超出索引范围的下标访问                  | `let v = vec![1, 2, 3]; println!(\"{}\", v[5]);` |\n",
    "| `unwrap`/`expect` 失败           | 在 `None` 或 `Err` 上调用 `unwrap`/`expect` | `let opt: Option<i32> = None; opt.unwrap();`   |\n",
    "| 整数除以零                       | 运行时执行除以零                            | `let x = 42 / 0;`                              |\n",
    "| `unreachable!`/`todo!` 等        | 表示不可达代码或尚未实现的分支              | `todo!(\"Implement later\");`                    |\n",
    "| `assert!`/`assert_eq!` 失败      | 断言条件不满足                              | `assert_eq!(2 + 2, 5);`                        |\n",
    "| 容器非法操作（如移除空容器元素） | 内部断言失败触发 panic                      | `let mut v: Vec<i32> = vec![]; v.remove(0);`   |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 被动触发"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:35:6:\n",
      "index out of bounds: the len is 3 but the index is 99\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: core::panicking::panic_bounds_check\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:280:5\n",
      "   3: ctx::run_user_code_5::{{closure}}\n",
      "   4: __rust_try.llvm.115191001341287182\n",
      "   5: std::panic::catch_unwind\n",
      "   6: run_user_code_5\n",
      "   7: evcxr::runtime::Runtime::run_loop\n",
      "   8: evcxr::runtime::runtime_hook\n",
      "   9: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "// 数组访问越界\n",
    "\n",
    "{\n",
    "    let v = vec![1, 2, 3];\n",
    "\n",
    "    v[99];\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 主动调用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在某些特殊场景中，开发者想要主动抛出一个异常，例如开头提到的在系统启动阶段读取文件失败。\n",
    "\n",
    "对此，Rust 为我们提供了 `panic!` 宏，当调用执行该宏时，**程序会打印出一个错误信息，展开报错点往前的函数调用堆栈，最后退出程序**。\n",
    "\n",
    "> 切记，一定是不可恢复的错误，才调用 `panic!` 处理，你总不想系统仅仅因为用户随便传入一个非法参数就崩溃吧？所以，**只有当你不知道该如何处理时，再去调用 panic!**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:33:5:\n",
      "crash and burn\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: <unknown>\n",
      "   3: <unknown>\n",
      "   4: <unknown>\n",
      "   5: <unknown>\n",
      "   6: evcxr::runtime::Runtime::run_loop\n",
      "   7: evcxr::runtime::runtime_hook\n",
      "   8: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    panic!(\"crash and burn\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### backtrace 栈展开"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一次栈展开（也称栈回溯），它包含了函数调用的顺序，当然按照逆序排列：最近调用的函数排在列表的最上方"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### panic 时的两种终止方式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当出现 `panic!` 时，程序提供了两种方式来处理终止流程：**栈展开**和**直接终止**。\n",
    "\n",
    "其中，默认的方式就是 `栈展开`，这意味着 Rust 会回溯栈上数据和函数调用，因此也意味着更多的善后工作，好处是可以给出充分的报错信息和栈调用信息，便于事后的问题复盘。`直接终止`，顾名思义，不清理数据就直接退出程序，善后工作交与操作系统来负责。\n",
    "\n",
    "对于绝大多数用户，使用默认选择是最好的，但是当你关心最终编译出的二进制可执行文件大小时，那么可以尝试去使用直接终止的方式，例如下面的配置修改 `Cargo.toml` 文件，实现在 [`release`](https://course.rs/first-try/cargo.html#手动编译和运行项目) 模式下遇到 `panic` 直接终止：\n",
    "\n",
    "```toml\n",
    "[profile.release]\n",
    "panic = 'abort'\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 线程 panic 后，程序是否会终止？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "长话短说，如果是 `main` 线程，则程序会终止，如果是其它子线程，该线程会终止，但是不会影响 `main` 线程。因此，尽量不要在 `main` 线程中做太多任务，将这些任务交由子线程去做，就算子线程 `panic` 也不会导致整个程序的结束。\n",
    "\n",
    "具体解析见 [panic 原理剖析](https://course.rs/basic/result-error/panic.html#panic-原理剖析)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 何时该使用 panic!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 合理区分可恢复与不可恢复的错误，是 Rust 错误处理的核心。只有当程序确实无法继续时，再选择 `panic!` 作为最终手段。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`panic!` 常用于处理那些无法或不应该在运行时恢复的严重错误。为了更好地理解其适用场景，我们先回顾 Rust 中的错误处理方式，再来总结 `panic!` 的典型用法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**`Result<T, E>`**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Rust 通过 `Result<T, E>` 枚举来表示可能成功或失败的操作结果："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enum Result<T, E> {\n",
    "    Ok(T), // 返回 `Ok(T)`，并携带成功结果。\n",
    "    Err(E), // 返回 `Err(E)`，携带错误信息，供调用方处理。\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于 `Result`，我们有多种处理策略，最直接的是 `unwrap` 与 `expect`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::net::IpAddr;\n",
    "\n",
    "let home: IpAddr = \"127.0.0.1\".parse().unwrap(); // `parse` 返回 `Result<IpAddr, E>`。如果解析成功，`unwrap` 返回 `IpAddr`；若失败，程序直接触发 `panic!`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**`panic!` 的典型使用场景**\n",
    "\n",
    "1. **不可恢复的逻辑错误**<br>\n",
    "当程序遇到严重的逻辑漏洞或不可能恢复的状态时，使用 `panic!` 明确中止运行，以避免产生错误结果或未知状态。\n",
    "2. **测试与原型开发阶段**<br>\n",
    "使用 `unwrap` 或 `expect` 快速定位错误，便于在开发早期发现潜在问题。随着代码成熟，再逐步替换为更健壮的错误处理。\n",
    "3. **初始化失败且无法继续运行**<br>\n",
    "程序刚启动就依赖一些关键资源，如果无法正确加载（例如配置文件缺失且无默认值），可以直接 `panic!`，因为继续运行没有意义。\n",
    "4. **示例代码或脚手架程序**<br>\n",
    " 在教学示例、脚本或一次性工具中，为了简洁，常直接使用 `unwrap` 或 `expect`，让错误尽快暴露。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**建议与实践**\n",
    "\n",
    "- 对外部输入或运行时可能出错的操作，尽量探索 `match`、`?` 运算符等友好的错误处理方式，避免草率 `panic!`。\n",
    "- 在库代码中，优先返回 `Result` 让调用者决定如何处理错误，只有在误用 API 的情况下才考虑 `panic!`。\n",
    "- 使用 `expect(\"错误原因说明\")` 能提供更具可读性的错误信息，对调试非常有帮助。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 返回值 Result 和?\n",
    "\n",
    "- https://course.rs/basic/result-error/result.html\n",
    "- https://practice-zh.course.rs/result-panic/panic.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/result-panic/panic.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在处理诸如文件读写、网络通信等常见操作时，我们经常会遇到**可以恢复的错误**。与会导致程序崩溃的严重错误不同，这类错误通常只影响当前操作，不必让整个程序停止。Rust 为此提供了 `Result<T, E>` 类型，用于表达“成功或失败”的结果，并鼓励调用者显式处理错误。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "enum Result<T, E> {\n",
    "    Ok(T), // 返回 `Ok(T)`，并携带成功结果。\n",
    "    Err(E), // 返回 `Err(E)`，携带错误信息，供调用方处理。\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 读取文件\n",
    "\n",
    "use std::fs::File;\n",
    "\n",
    "fn main() {\n",
    "    let f = File::open(\"hello.txt\");\n",
    "\n",
    "    let f = match f {\n",
    "        Ok(file) => file,\n",
    "        Err(error) => {\n",
    "            panic!(\"Problem opening the file: {:?}\", error)\n",
    "        },\n",
    "    };\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. `File::open` 返回 `Result<std::fs::File, std::io::Error>`：\n",
    "   - 成功时提供文件句柄。\n",
    "   - 失败时返回 IO 错误（如文件不存在、无权限等）。\n",
    "2. 使用 `match` 解构：\n",
    "   - `Ok(file)` 分支取得可用的文件句柄。\n",
    "   - `Err(error)` 分支目前仍调用 `panic!`，但在真正的服务器或需要稳定性的程序中，应改用更稳健的错误处理策略。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如何确认返回类型？\n",
    "\n",
    "- **查阅文档**：标准库或第三方库文档会列出函数签名。\n",
    "- **IDE 辅助**：VS Code + `rust-analyzer` 能直接显示类型提示并支持跳转。\n",
    "- **借助编译器提示**：故意写错类型，让编译器报错并提供正确的类型信息。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "关键要点\n",
    "\n",
    "- **可恢复错误**不应直接 `panic!`，尤其是在服务器场景中，单次失败不应拖垮整体服务。\n",
    "- `Result<T, E>` 允许调用者决定：重试、忽略、或向上传递错误信息。\n",
    "- `std::io::Error` 等错误类型提供了详尽信息，可用于记录日志、用户提示或自定义恢复策略。\n",
    "- 使用 `match`、`?` 运算符、或自定义错误处理逻辑，让代码在面对异常时仍保持健壮。\n",
    "\n",
    "通过合理地利用 `Result`，你可以编写更加可靠、可维护的 Rust 应用，为各种异常状况预留处理空间，而不是一遇到问题就“全体崩溃”。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 对返回的错误进行处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fs::File;\n",
    "use std::io::ErrorKind;\n",
    "\n",
    "fn main() {\n",
    "    let f = File::open(\"hello.txt\");\n",
    "\n",
    "    let f = match f {\n",
    "        Ok(file) => file,\n",
    "        Err(error) => match error.kind() { // 需要对部分错误进行特殊处理，而不是所有错误都直接崩溃\n",
    "            ErrorKind::NotFound => match File::create(\"hello.txt\") { // 如果是文件不存在错误 ErrorKind::NotFound，就创建文件\n",
    "                Ok(fc) => fc, // 创建成功，将新的文件句柄赋值给 f\n",
    "                Err(e) => panic!(\"Problem creating the file: {:?}\", e), // 如果失败，则 panic\n",
    "            },\n",
    "            other_error => panic!(\"Problem opening the file: {:?}\", other_error), // 剩下的错误，一律 panic\n",
    "        },\n",
    "    };\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "虽然很清晰，但是代码还是有些啰嗦，我们会在[简化错误处理](https://course.rs/advance/errors.html)一章重点讲述如何写出更优雅的错误。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 失败就 panic: unwrap 和 expect"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在快速原型、示例代码或暂时不想处理错误的场景里，我们希望简化 `Result<T, E>` 的处理方式。`unwrap` 与 `expect` 正好提供了这样的捷径：**成功时提取值，失败时立刻 `panic!`**。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**`unwrap`**\n",
    "- **成功**：返回 `Ok(T)` 中的值。\n",
    "- **失败**：直接触发 `panic!`，包含默认的错误信息。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:37:37:\n",
      "called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: core::result::unwrap_failed\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/result.rs:1765:5\n",
      "   3: <unknown>\n",
      "   4: <unknown>\n",
      "   5: evcxr::runtime::Runtime::run_loop\n",
      "   6: evcxr::runtime::runtime_hook\n",
      "   7: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "use std::fs::File;\n",
    "\n",
    "{\n",
    "    let f = File::open(\"hello.txt\").unwrap();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**`expect`**\n",
    "- 行为与 `unwrap` 相同，但允许插入**自定义错误提示**。\n",
    "- 更适合需要明确说明失败原因的场景。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:37:37:\n",
      "Failed to open hello.txt: Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: core::result::unwrap_failed\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/result.rs:1765:5\n",
      "   3: <unknown>\n",
      "   4: <unknown>\n",
      "   5: evcxr::runtime::Runtime::run_loop\n",
      "   6: evcxr::runtime::runtime_hook\n",
      "   7: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "use std::fs::File;\n",
    "\n",
    "{\n",
    "    let f = File::open(\"hello.txt\").expect(\"Failed to open hello.txt\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **何时使用**：快速验证、示例代码、初期开发阶段或确保不会失败的操作。\n",
    "- **何时避免**：生产环境、需要可靠性或涉及用户输入/外部资源的情况，应改用显式错误处理（`match`、`?` 等）。\n",
    "\n",
    "`unwrap` 和 `expect` 是 Rust 开发中的“速效胶水”，能在合适的场合快速解决问题，但在正式场景下仍应谨慎使用，防止无意中让整个程序崩溃。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> Debug 下 `panic!`，Release 下优雅兜底\n",
    "\n",
    "通过自定义宏（或扩展 trait），你可以：\n",
    "\n",
    "- 保留 Debug 阶段“失败就崩”的快速反馈。\n",
    "- 在 Release 中提供更温和的错误处理，避免整服务宕机。\n",
    "- 在实际项目里逐步将原有的 `unwrap` / `expect` 替换为 `dev_unwrap!` 即可。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "Shell command failed with exit code 101: \nthread 'main' panicked at src/main.rs:28:5:\nAPP_SECRET must be set: NotPresent\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n",
     "output_type": "error",
     "traceback": [
      "Shell command failed with exit code 101: \nthread 'main' panicked at src/main.rs:28:5:\nAPP_SECRET must be set: NotPresent\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n"
     ]
    }
   ],
   "source": [
    "! cd dev-unwrap && cargo run -q"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Using secret: release-default-secret\n",
       "Listening on port: 8080\n",
       "WARN: APP_SECRET must be set: environment variable not found\n",
       "WARN: APP_PORT must be set: environment variable not found\n"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd dev-unwrap && cargo run -q --release"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 传播错误\n",
    "\n",
    "要点速记\n",
    "\n",
    "- **传播错误**是 Rust 错误处理的常态：底层函数把错误逐层向上交给最合适的调用方解决。\n",
    "- `?` 是处理 `Result/Option` 的强力语法糖：遇 `Err`/`None` 立即返回，遇成功值继续执行。\n",
    "- 函数返回类型需要与 `?` 匹配，必要时调整 `main` 签名或用自定义错误类型。\n",
    "- `?` 支持错误类型自动转换，配合 `From` 机制构建统一的错误体系。\n",
    "- `Option` 也适用 `?`，但要注意返回值的包装方式。\n",
    "- `try!` 已经是历史，请拥抱 `?`。\n",
    "\n",
    "掌握这些技巧，你就能写出既简洁又健壮的错误传播代码，让调用链上的责任分配清晰明确。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "为何需要传播错误？\n",
    "\n",
    "- 实际项目中，函数调用链很长，错误往往需要 **层层上传**。\n",
    "- 某个底层操作（如文件 I/O）失败，通常不是当场 `panic!`，而是交给上层决定：继续传播、转换后再处理、或反馈给用户。\n",
    "- 因此函数常返回 `Result<T, E>`，由调用者根据上下文作出决策。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "手写 match 的经典写法（啰嗦但直观）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fs::File;\n",
    "use std::io::{self, Read};\n",
    "\n",
    "// 成功路径与失败路径清晰，但重复代码多、冗长\n",
    "fn read_username_from_file() -> Result<String, io::Error> {\n",
    "    // 打开文件，f是`Result<文件句柄,io::Error>`\n",
    "    let f = File::open(\"hello.txt\");\n",
    "\n",
    "    let mut f = match f {\n",
    "        // 打开文件成功，将file句柄赋值给f\n",
    "        Ok(file) => file,\n",
    "        // 打开文件失败，将错误返回(向上传播)\n",
    "        Err(e) => return Err(e),\n",
    "    };\n",
    "    // 创建动态字符串s\n",
    "    let mut s = String::new();\n",
    "    // 从f文件句柄读取数据并写入s中\n",
    "    match f.read_to_string(&mut s) {\n",
    "        // 读取成功，返回Ok封装的字符串\n",
    "        Ok(_) => Ok(s),\n",
    "        // 将错误向上传播\n",
    "        Err(e) => Err(e),\n",
    "    }\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### * `?` 运算符"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn read_username_from_file() -> Result<String, io::Error> {\n",
    "    let mut f = File::open(\"hello.txt\")?;\n",
    "    let mut s = String::new();\n",
    "    f.read_to_string(&mut s)?;\n",
    "    Ok(s)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `?` 遇 `Err` 时立刻返回，遇 `Ok` 则解包成功值。\n",
    "- 效果等价于上面的 `match`，却大幅减少样板代码。\n",
    "- 还能链式调用，使代码更加精简：\n",
    "- 更“狠”一刀：直接用标准库封装的 `fs::read_to_string(\"hello.txt\")`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn read_username_from_file() -> Result<String, io::Error> {\n",
    "    let mut s = String::new();\n",
    "    File::open(\"hello.txt\")?.read_to_string(&mut s)?; // 链式调用\n",
    "    Ok(s)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### `?` 的“类型提升”能力\n",
    "\n",
    "- 虽然 `File::open` 返回 `Result<File, io::Error>`，但 `?` 可自动通过 `From` 实现将其转换为更通用的错误类型（例如 `Box<dyn Error>`）。\n",
    "- 这依赖于标准库 `From`/`Into` 特征的实现，是简化错误泛化的关键。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn open_file() -> Result<File, Box<dyn std::error::Error>> {\n",
    "    let f = File::open(\"hello.txt\")?;\n",
    "    Ok(f)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### `?` 也能用于 `Option`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "⚠️ **常见错误**：直接写 `arr.get(0)?` 作为函数返回值会编译失败，必须将 `Some` 显式包回去，或将 `?` 用在中间绑定/链式调用中。\n",
    "- `?` 会把 `Option`/`Result` **拆开**，把里面的成功值取出来继续执行。\n",
    "- 因此直接写 `arr.get(0)?` 会让函数最后的返回值变成裸类型（`&i32`），与声明的 `Option<&i32>` 不一致。\n",
    "- 如果要用 `?`，要么在中间绑定中使用它，要么在拆箱后再显式包回 `Some`，或者像例子那样把它放在链式调用的中间，让最终表达式的类型仍然是 `Option<_>`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "`?` operator has incompatible types",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0308] Error:\u001b[0m `?` operator has incompatible types",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_22:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249m[\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m]\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mO\u001b[0m\u001b[38;5;100mp\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100mo\u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;100m<\u001b[0m\u001b[38;5;100m&\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100m3\u001b[0m\u001b[38;5;100m2\u001b[0m\u001b[38;5;100m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                          \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m expected `Option<&i32>` because of return type",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54m.\u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m0\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;54m?\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected `Option<&i32>`, found `&i32`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "unused variable: `f`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[unused_variables] Error:\u001b[0m unused variable: `f`"
     ]
    }
   ],
   "source": [
    "fn first(arr: &[i32]) -> Option<&i32> {\n",
    "    arr.get(0)? // ? 拿走了 Some 这一层包装，留下内部的值。当你把 arr.get(0)? 作为函数的最后一行返回时，返回的其实是 &i32，而函数声明的返回类型却是 Option<&i32>\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn first(arr: &[i32]) -> Option<&i32> {\n",
    "    arr.get(0)\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 若使用 `?`; `?` 能直接在返回 `Option` 的函数中传播 `None`，支持链式组合\n",
    "\n",
    "fn last_char_of_first_line(text: &str) -> Option<char> {\n",
    "    text.lines().next()?.chars().last() // text.lines().next() 返回 Option<&str>; ? 拿到 &str 后，继续调用 .chars().last()\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### `?` 的使用前提"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 函数必须返回 `Result`、`Option` 或其他实现了 `Try`/`FromResidual` 的类型。\n",
    "- `main` 默认返回 `()`，不能使用 `?`，除非调整签名："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() -> Result<(), Box<dyn std::error::Error>> {\n",
    "    File::open(\"hello.txt\")?;\n",
    "    Ok(())\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Rust",
   "language": "rust",
   "name": "rust"
  },
  "language_info": {
   "codemirror_mode": "rust",
   "file_extension": ".rs",
   "mimetype": "text/rust",
   "name": "rust",
   "pygment_lexer": "rust",
   "version": ""
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
